From 541e316aed6f7d6efeb427a88645c2a8f61418d6 Mon Sep 17 00:00:00 2001 From: Stephen Evanchik <evanchsa@gmail.com> Date: Mon, 8 Aug 2005 01:26:18 -0500 Subject: [PATCH 001/563] Input: psmouse - add support for IBM TrackPoint devices. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/mouse/Makefile | 2 +- drivers/input/mouse/psmouse-base.c | 15 +- drivers/input/mouse/psmouse.h | 1 + drivers/input/mouse/trackpoint.c | 297 +++++++++++++++++++++++++++++ drivers/input/mouse/trackpoint.h | 147 ++++++++++++++ 5 files changed, 460 insertions(+), 2 deletions(-) create mode 100644 drivers/input/mouse/trackpoint.c create mode 100644 drivers/input/mouse/trackpoint.h diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index c4909b49337d2..82b330bbf068d 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o -psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o +psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o trackpoint.o diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 2bb2fe78bdca9..b3508276785f0 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -25,6 +25,7 @@ #include "logips2pp.h" #include "alps.h" #include "lifebook.h" +#include "trackpoint.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -519,6 +520,12 @@ static int psmouse_extensions(struct psmouse *psmouse, if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0) return PSMOUSE_IMPS; +/* + * Try to initialize the IBM TrackPoint + */ + if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0) + return PSMOUSE_TRACKPOINT; + /* * Okay, all failed, we have a standard mouse here. The number of the buttons * is still a question, though. We assume 3. @@ -599,6 +606,12 @@ static struct psmouse_protocol psmouse_protocols[] = { .alias = "lifebook", .init = lifebook_init, }, + { + .type = PSMOUSE_TRACKPOINT, + .name = "TPPS/2", + .alias = "trackpoint", + .detect = trackpoint_detect, + }, { .type = PSMOUSE_AUTO, .name = "auto", @@ -1234,7 +1247,7 @@ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) *((unsigned int *)kp->arg) = proto->type; - return 0; \ + return 0; } static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 86691cf43433f..e312a6b416811 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -78,6 +78,7 @@ enum psmouse_type { PSMOUSE_SYNAPTICS, PSMOUSE_ALPS, PSMOUSE_LIFEBOOK, + PSMOUSE_TRACKPOINT, PSMOUSE_AUTO /* This one should always be last */ }; diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c new file mode 100644 index 0000000000000..aee3b24a91026 --- /dev/null +++ b/drivers/input/mouse/trackpoint.c @@ -0,0 +1,297 @@ +/* + * Stephen Evanchik <evanchsa@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Trademarks are the property of their respective owners. + */ + +#include <linux/delay.h> +#include <linux/serio.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/input.h> +#include <linux/libps2.h> +#include <linux/proc_fs.h> +#include <asm/uaccess.h> +#include "psmouse.h" +#include "trackpoint.h" + +PSMOUSE_DEFINE_ATTR(sensitivity); +PSMOUSE_DEFINE_ATTR(speed); +PSMOUSE_DEFINE_ATTR(inertia); +PSMOUSE_DEFINE_ATTR(reach); +PSMOUSE_DEFINE_ATTR(draghys); +PSMOUSE_DEFINE_ATTR(mindrag); +PSMOUSE_DEFINE_ATTR(thresh); +PSMOUSE_DEFINE_ATTR(upthresh); +PSMOUSE_DEFINE_ATTR(ztime); +PSMOUSE_DEFINE_ATTR(jenks); +PSMOUSE_DEFINE_ATTR(press_to_select); +PSMOUSE_DEFINE_ATTR(skipback); +PSMOUSE_DEFINE_ATTR(ext_dev); + +#define MAKE_ATTR_READ(_item) \ + static ssize_t psmouse_attr_show_##_item(struct psmouse *psmouse, char *buf) \ + { \ + struct trackpoint_data *tp = psmouse->private; \ + return sprintf(buf, "%lu\n", (unsigned long)tp->_item); \ + } + +#define MAKE_ATTR_WRITE(_item, command) \ + static ssize_t psmouse_attr_set_##_item(struct psmouse *psmouse, const char *buf, size_t count) \ + { \ + char *rest; \ + unsigned long value; \ + struct trackpoint_data *tp = psmouse->private; \ + value = simple_strtoul(buf, &rest, 10); \ + if (*rest) \ + return -EINVAL; \ + tp->_item = value; \ + trackpoint_write(&psmouse->ps2dev, command, tp->_item); \ + return count; \ + } + +#define MAKE_ATTR_TOGGLE(_item, command, mask) \ + static ssize_t psmouse_attr_set_##_item(struct psmouse *psmouse, const char *buf, size_t count) \ + { \ + unsigned char toggle; \ + struct trackpoint_data *tp = psmouse->private; \ + toggle = (buf[0] == '1') ? 1 : 0; \ + if (toggle != tp->_item) { \ + tp->_item = toggle; \ + trackpoint_toggle_bit(&psmouse->ps2dev, command, mask); \ + } \ + return count; \ + } + +/* + * Device IO: read, write and toggle bit + */ +static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned char *results) +{ + if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || + ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) { + return -1; + } + + return 0; +} + +static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned char val) +{ + if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) { + return -1; + } + + return 0; +} + +static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsigned char mask) +{ + /* Bad things will happen if the loc param isn't in this range */ + if (loc < 0x20 || loc >= 0x2F) + return -1; + + if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) { + return -1; + } + + return 0; +} + +MAKE_ATTR_WRITE(sensitivity, TP_SENS); +MAKE_ATTR_READ(sensitivity); + +MAKE_ATTR_WRITE(speed, TP_SPEED); +MAKE_ATTR_READ(speed); + +MAKE_ATTR_WRITE(inertia, TP_INERTIA); +MAKE_ATTR_READ(inertia); + +MAKE_ATTR_WRITE(reach, TP_REACH); +MAKE_ATTR_READ(reach); + +MAKE_ATTR_WRITE(draghys, TP_DRAGHYS); +MAKE_ATTR_READ(draghys); + +MAKE_ATTR_WRITE(mindrag, TP_MINDRAG); +MAKE_ATTR_READ(mindrag); + +MAKE_ATTR_WRITE(thresh, TP_THRESH); +MAKE_ATTR_READ(thresh); + +MAKE_ATTR_WRITE(upthresh, TP_UP_THRESH); +MAKE_ATTR_READ(upthresh); + +MAKE_ATTR_WRITE(ztime, TP_Z_TIME); +MAKE_ATTR_READ(ztime); + +MAKE_ATTR_WRITE(jenks, TP_JENKS_CURV); +MAKE_ATTR_READ(jenks); + +MAKE_ATTR_TOGGLE(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON); +MAKE_ATTR_READ(press_to_select); + +MAKE_ATTR_TOGGLE(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); +MAKE_ATTR_READ(skipback); + +MAKE_ATTR_TOGGLE(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); +MAKE_ATTR_READ(ext_dev); + +static struct attribute *trackpoint_attrs[] = { + &psmouse_attr_sensitivity.attr, + &psmouse_attr_speed.attr, + &psmouse_attr_inertia.attr, + &psmouse_attr_reach.attr, + &psmouse_attr_draghys.attr, + &psmouse_attr_mindrag.attr, + &psmouse_attr_thresh.attr, + &psmouse_attr_upthresh.attr, + &psmouse_attr_ztime.attr, + &psmouse_attr_jenks.attr, + &psmouse_attr_press_to_select.attr, + &psmouse_attr_skipback.attr, + &psmouse_attr_ext_dev.attr, + NULL +}; + +static struct attribute_group trackpoint_attr_group = { + .attrs = trackpoint_attrs, +}; + +static void trackpoint_disconnect(struct psmouse *psmouse) +{ + sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group); + + kfree(psmouse->private); + psmouse->private = NULL; +} + +static int trackpoint_sync(struct psmouse *psmouse) +{ + unsigned char toggle; + struct trackpoint_data *tp = psmouse->private; + + if (!tp) + return -1; + + /* Disable features that may make device unusable with this driver */ + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle); + if (toggle & TP_MASK_TWOHAND) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, TP_MASK_TWOHAND); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, &toggle); + if (toggle & TP_MASK_SOURCE_TAG) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, TP_MASK_SOURCE_TAG); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle); + if (toggle & TP_MASK_MB) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB); + + /* Push the config to the device */ + trackpoint_write(&psmouse->ps2dev, TP_SENS, tp->sensitivity); + trackpoint_write(&psmouse->ps2dev, TP_INERTIA, tp->inertia); + trackpoint_write(&psmouse->ps2dev, TP_SPEED, tp->speed); + + trackpoint_write(&psmouse->ps2dev, TP_REACH, tp->reach); + trackpoint_write(&psmouse->ps2dev, TP_DRAGHYS, tp->draghys); + trackpoint_write(&psmouse->ps2dev, TP_MINDRAG, tp->mindrag); + + trackpoint_write(&psmouse->ps2dev, TP_THRESH, tp->thresh); + trackpoint_write(&psmouse->ps2dev, TP_UP_THRESH, tp->upthresh); + + trackpoint_write(&psmouse->ps2dev, TP_Z_TIME, tp->ztime); + trackpoint_write(&psmouse->ps2dev, TP_JENKS_CURV, tp->jenks); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_PTSON, &toggle); + if (((toggle & TP_MASK_PTSON) == TP_MASK_PTSON) != tp->press_to_select) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_PTSON, TP_MASK_PTSON); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, &toggle); + if (((toggle & TP_MASK_SKIPBACK) == TP_MASK_SKIPBACK) != tp->skipback) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, &toggle); + if (((toggle & TP_MASK_EXT_DEV) == TP_MASK_EXT_DEV) != tp->ext_dev) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); + + return 0; +} + +static void trackpoint_defaults(struct trackpoint_data *tp) +{ + tp->press_to_select = TP_DEF_PTSON; + tp->sensitivity = TP_DEF_SENS; + tp->speed = TP_DEF_SPEED; + tp->reach = TP_DEF_REACH; + + tp->draghys = TP_DEF_DRAGHYS; + tp->mindrag = TP_DEF_MINDRAG; + + tp->thresh = TP_DEF_THRESH; + tp->upthresh = TP_DEF_UP_THRESH; + + tp->ztime = TP_DEF_Z_TIME; + tp->jenks = TP_DEF_JENKS_CURV; + + tp->inertia = TP_DEF_INERTIA; + tp->skipback = TP_DEF_SKIPBACK; + tp->ext_dev = TP_DEF_EXT_DEV; +} + +int trackpoint_detect(struct psmouse *psmouse, int set_properties) +{ + struct trackpoint_data *priv; + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char firmware_id; + unsigned char button_info; + unsigned char param[2]; + + param[0] = param[1] = 0; + + if (ps2_command(ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID))) + return -1; + + if (param[0] != TP_MAGIC_IDENT) + return -1; + + if (!set_properties) + return 0; + + firmware_id = param[1]; + + if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) { + printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n"); + button_info = 0; + } + + psmouse->private = priv = kcalloc(1, sizeof(struct trackpoint_data), GFP_KERNEL); + if (!priv) + return -1; + + psmouse->vendor = "IBM"; + psmouse->name = "TrackPoint"; + + psmouse->reconnect = trackpoint_sync; + psmouse->disconnect = trackpoint_disconnect; + + trackpoint_defaults(priv); + trackpoint_sync(psmouse); + + sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); + + printk(KERN_INFO "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n", + firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f); + + return 0; +} + diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h new file mode 100644 index 0000000000000..9857d8b6ad665 --- /dev/null +++ b/drivers/input/mouse/trackpoint.h @@ -0,0 +1,147 @@ +/* + * IBM TrackPoint PS/2 mouse driver + * + * Stephen Evanchik <evanchsa@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifndef _TRACKPOINT_H +#define _TRACKPOINT_H + +/* + * These constants are from the TrackPoint System + * Engineering documentation Version 4 from IBM Watson + * research: + * http://wwwcssrv.almaden.ibm.com/trackpoint/download.html + */ + +#define TP_COMMAND 0xE2 /* Commands start with this */ + +#define TP_READ_ID 0xE1 /* Sent for device identification */ +#define TP_MAGIC_IDENT 0x01 /* Sent after a TP_READ_ID followed */ + /* by the firmware ID */ + + +/* + * Commands + */ +#define TP_RECALIB 0x51 /* Recalibrate */ +#define TP_POWER_DOWN 0x44 /* Can only be undone through HW reset */ +#define TP_EXT_DEV 0x21 /* Determines if external device is connected (RO) */ +#define TP_EXT_BTN 0x4B /* Read extended button status */ +#define TP_POR 0x7F /* Execute Power on Reset */ +#define TP_POR_RESULTS 0x25 /* Read Power on Self test results */ +#define TP_DISABLE_EXT 0x40 /* Disable external pointing device */ +#define TP_ENABLE_EXT 0x41 /* Enable external pointing device */ + +/* + * Mode manipulation + */ +#define TP_SET_SOFT_TRANS 0x4E /* Set mode */ +#define TP_CANCEL_SOFT_TRANS 0xB9 /* Cancel mode */ +#define TP_SET_HARD_TRANS 0x45 /* Mode can only be set */ + + +/* + * Register oriented commands/properties + */ +#define TP_WRITE_MEM 0x81 +#define TP_READ_MEM 0x80 /* Not used in this implementation */ + +/* +* RAM Locations for properties + */ +#define TP_SENS 0x4A /* Sensitivity */ +#define TP_MB 0x4C /* Read Middle Button Status (RO) */ +#define TP_INERTIA 0x4D /* Negative Inertia */ +#define TP_SPEED 0x60 /* Speed of TP Cursor */ +#define TP_REACH 0x57 /* Backup for Z-axis press */ +#define TP_DRAGHYS 0x58 /* Drag Hysteresis */ + /* (how hard it is to drag */ + /* with Z-axis pressed) */ + +#define TP_MINDRAG 0x59 /* Minimum amount of force needed */ + /* to trigger dragging */ + +#define TP_THRESH 0x5C /* Minimum value for a Z-axis press */ +#define TP_UP_THRESH 0x5A /* Used to generate a 'click' on Z-axis */ +#define TP_Z_TIME 0x5E /* How sharp of a press */ +#define TP_JENKS_CURV 0x5D /* Minimum curvature for double click */ + +/* + * Toggling Flag bits + */ +#define TP_TOGGLE 0x47 /* Toggle command */ + +#define TP_TOGGLE_MB 0x23 /* Disable/Enable Middle Button */ +#define TP_MASK_MB 0x01 +#define TP_TOGGLE_EXT_DEV 0x23 /* Toggle external device */ +#define TP_MASK_EXT_DEV 0x02 +#define TP_TOGGLE_DRIFT 0x23 /* Drift Correction */ +#define TP_MASK_DRIFT 0x80 +#define TP_TOGGLE_BURST 0x28 /* Burst Mode */ +#define TP_MASK_BURST 0x80 +#define TP_TOGGLE_PTSON 0x2C /* Press to Select */ +#define TP_MASK_PTSON 0x01 +#define TP_TOGGLE_HARD_TRANS 0x2C /* Alternate method to set Hard Transparency */ +#define TP_MASK_HARD_TRANS 0x80 +#define TP_TOGGLE_TWOHAND 0x2D /* Two handed */ +#define TP_MASK_TWOHAND 0x01 +#define TP_TOGGLE_STICKY_TWO 0x2D /* Sticky two handed */ +#define TP_MASK_STICKY_TWO 0x04 +#define TP_TOGGLE_SKIPBACK 0x2D /* Suppress movement after drag release */ +#define TP_MASK_SKIPBACK 0x08 +#define TP_TOGGLE_SOURCE_TAG 0x20 /* Bit 3 of the first packet will be set to + to the origin of the packet (external or TP) */ +#define TP_MASK_SOURCE_TAG 0x80 +#define TP_TOGGLE_EXT_TAG 0x22 /* Bit 3 of the first packet coming from the + external device will be forced to 1 */ +#define TP_MASK_EXT_TAG 0x04 + + +/* Power on Self Test Results */ +#define TP_POR_SUCCESS 0x3B + +/* + * Default power on values + */ +#define TP_DEF_SENS 0x80 +#define TP_DEF_INERTIA 0x06 +#define TP_DEF_SPEED 0x61 +#define TP_DEF_REACH 0x0A + +#define TP_DEF_DRAGHYS 0xFF +#define TP_DEF_MINDRAG 0x14 + +#define TP_DEF_THRESH 0x08 +#define TP_DEF_UP_THRESH 0xFF +#define TP_DEF_Z_TIME 0x26 +#define TP_DEF_JENKS_CURV 0x87 + +/* Toggles */ +#define TP_DEF_MB 0x00 +#define TP_DEF_PTSON 0x00 +#define TP_DEF_SKIPBACK 0x00 +#define TP_DEF_EXT_DEV 0x01 + +#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd)) + +struct trackpoint_data +{ + unsigned char sensitivity, speed, inertia, reach; + unsigned char draghys, mindrag; + unsigned char thresh, upthresh; + unsigned char ztime, jenks; + + unsigned char press_to_select; + unsigned char skipback; + + unsigned char ext_dev; +}; + +extern int trackpoint_detect(struct psmouse *psmouse, int set_properties); + +#endif /* _TRACKPOINT_H */ -- GitLab From b1b5d7f9b7ac6a8e3452ac43a53eebf69fdf5a77 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp <shaggy@austin.ibm.com> Date: Tue, 30 Aug 2005 14:28:56 -0500 Subject: [PATCH 002/563] JFS: jfs_delete_inode should always call clear_inode. Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com> --- fs/jfs/inode.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 767c7ecb429ed..37da3e33e7506 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -128,21 +128,21 @@ void jfs_delete_inode(struct inode *inode) { jfs_info("In jfs_delete_inode, inode = 0x%p", inode); - if (is_bad_inode(inode) || - (JFS_IP(inode)->fileset != cpu_to_le32(FILESYSTEM_I))) - return; + if (!is_bad_inode(inode) && + (JFS_IP(inode)->fileset == cpu_to_le32(FILESYSTEM_I))) { - if (test_cflag(COMMIT_Freewmap, inode)) - jfs_free_zero_link(inode); + if (test_cflag(COMMIT_Freewmap, inode)) + jfs_free_zero_link(inode); - diFree(inode); + diFree(inode); - /* - * Free the inode from the quota allocation. - */ - DQUOT_INIT(inode); - DQUOT_FREE_INODE(inode); - DQUOT_DROP(inode); + /* + * Free the inode from the quota allocation. + */ + DQUOT_INIT(inode); + DQUOT_FREE_INODE(inode); + DQUOT_DROP(inode); + } clear_inode(inode); } -- GitLab From dc90e95f310f4f821c905b2aec8e9449bb3270fa Mon Sep 17 00:00:00 2001 From: Peter Chubb <peterc@gelato.unsw.edu.au> Date: Wed, 24 Aug 2005 17:13:00 -0700 Subject: [PATCH 003/563] [IA64] Add PAL_VM_SUMMARY/PAL_MEM_ATTRIB to bootloader for SKI This patch implements PAL_VM_SUMMARY (and PAL_MEM_ATTRIB for good measure) and pretends that the simulated machine is a McKinley. Some extra comments and clean-up by Tony Luck. Signed-off-by: Peter Chubb <peterc@gelato.unsw.edu.au> Signed-off-by: Tony Luck <tony.luck@intel.com> --- arch/ia64/hp/sim/boot/boot_head.S | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/arch/ia64/hp/sim/boot/boot_head.S b/arch/ia64/hp/sim/boot/boot_head.S index 1c8c7e6a9a5ec..a9bd71ac78e2d 100644 --- a/arch/ia64/hp/sim/boot/boot_head.S +++ b/arch/ia64/hp/sim/boot/boot_head.S @@ -4,6 +4,7 @@ */ #include <asm/asmmacro.h> +#include <asm/pal.h> .bss .align 16 @@ -49,7 +50,11 @@ GLOBAL_ENTRY(jmp_to_kernel) br.sptk.few b7 END(jmp_to_kernel) - +/* + * r28 contains the index of the PAL function + * r29--31 the args + * Return values in ret0--3 (r8--11) + */ GLOBAL_ENTRY(pal_emulator_static) mov r8=-1 mov r9=256 @@ -62,7 +67,7 @@ GLOBAL_ENTRY(pal_emulator_static) cmp.gtu p6,p7=r9,r28 (p6) br.cond.sptk.few stacked ;; -static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ +static: cmp.eq p6,p7=PAL_PTCE_INFO,r28 (p7) br.cond.sptk.few 1f ;; mov r8=0 /* status = 0 */ @@ -70,21 +75,21 @@ static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ movl r10=0x0000000200000003 /* count[0], count[1] */ movl r11=0x1000000000002000 /* stride[0], stride[1] */ br.cond.sptk.few rp -1: cmp.eq p6,p7=14,r28 /* PAL_FREQ_RATIOS */ +1: cmp.eq p6,p7=PAL_FREQ_RATIOS,r28 (p7) br.cond.sptk.few 1f mov r8=0 /* status = 0 */ movl r9 =0x100000064 /* proc_ratio (1/100) */ movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ movl r11=0x100000064 /* itc_ratio<<32 (1/100) */ ;; -1: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */ +1: cmp.eq p6,p7=PAL_RSE_INFO,r28 (p7) br.cond.sptk.few 1f mov r8=0 /* status = 0 */ mov r9=96 /* num phys stacked */ mov r10=0 /* hints */ mov r11=0 br.cond.sptk.few rp -1: cmp.eq p6,p7=1,r28 /* PAL_CACHE_FLUSH */ +1: cmp.eq p6,p7=PAL_CACHE_FLUSH,r28 /* PAL_CACHE_FLUSH */ (p7) br.cond.sptk.few 1f mov r9=ar.lc movl r8=524288 /* flush 512k million cache lines (16MB) */ @@ -102,7 +107,7 @@ static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ mov ar.lc=r9 mov r8=r0 ;; -1: cmp.eq p6,p7=15,r28 /* PAL_PERF_MON_INFO */ +1: cmp.eq p6,p7=PAL_PERF_MON_INFO,r28 (p7) br.cond.sptk.few 1f mov r8=0 /* status = 0 */ movl r9 =0x08122f04 /* generic=4 width=47 retired=8 cycles=18 */ @@ -138,6 +143,20 @@ static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ st8 [r29]=r0,16 /* clear remaining bits */ st8 [r18]=r0,16 /* clear remaining bits */ ;; +1: cmp.eq p6,p7=PAL_VM_SUMMARY,r28 +(p7) br.cond.sptk.few 1f + mov r8=0 /* status = 0 */ + movl r9=0x2044040020F1865 /* num_tc_levels=2, num_unique_tcs=4 */ + /* max_itr_entry=64, max_dtr_entry=64 */ + /* hash_tag_id=2, max_pkr=15 */ + /* key_size=24, phys_add_size=50, vw=1 */ + movl r10=0x183C /* rid_size=24, impl_va_msb=60 */ + ;; +1: cmp.eq p6,p7=PAL_MEM_ATTRIB,r28 +(p7) br.cond.sptk.few 1f + mov r8=0 /* status = 0 */ + mov r9=0x80|0x01 /* NatPage|WB */ + ;; 1: br.cond.sptk.few rp stacked: br.ret.sptk.few rp -- GitLab From 714d2dc14914f0f7bb008effe830c99eb47c75df Mon Sep 17 00:00:00 2001 From: Peter Chubb <peterc@gelato.unsw.edu.au> Date: Thu, 25 Aug 2005 17:39:00 -0700 Subject: [PATCH 004/563] [IA64] Allow /proc/pal/cpu0/vm_info under the simulator Not all of the PAL VM calls are implemented for the SKI simulator. Don't just give up if one fails, print information from the calls that succeed. Signed-off-by: Peter Chubb <peterc@gelato.unsw.edu.au> Signed-off-by: Tony Luck <tony.luck@intel.com> --- arch/ia64/kernel/palinfo.c | 115 +++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 55 deletions(-) diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c index 25e7c83445640..89faa603c6be2 100644 --- a/arch/ia64/kernel/palinfo.c +++ b/arch/ia64/kernel/palinfo.c @@ -307,11 +307,9 @@ vm_info(char *page) if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) { printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status); - return 0; - } + } else { - - p += sprintf(p, + p += sprintf(p, "Physical Address Space : %d bits\n" "Virtual Address Space : %d bits\n" "Protection Key Registers(PKR) : %d\n" @@ -319,92 +317,99 @@ vm_info(char *page) "Hash Tag ID : 0x%x\n" "Size of RR.rid : %d\n", vm_info_1.pal_vm_info_1_s.phys_add_size, - vm_info_2.pal_vm_info_2_s.impl_va_msb+1, vm_info_1.pal_vm_info_1_s.max_pkr+1, - vm_info_1.pal_vm_info_1_s.key_size, vm_info_1.pal_vm_info_1_s.hash_tag_id, + vm_info_2.pal_vm_info_2_s.impl_va_msb+1, + vm_info_1.pal_vm_info_1_s.max_pkr+1, + vm_info_1.pal_vm_info_1_s.key_size, + vm_info_1.pal_vm_info_1_s.hash_tag_id, vm_info_2.pal_vm_info_2_s.rid_size); + } - if (ia64_pal_mem_attrib(&attrib) != 0) - return 0; - - p += sprintf(p, "Supported memory attributes : "); - sep = ""; - for (i = 0; i < 8; i++) { - if (attrib & (1 << i)) { - p += sprintf(p, "%s%s", sep, mem_attrib[i]); - sep = ", "; + if (ia64_pal_mem_attrib(&attrib) == 0) { + p += sprintf(p, "Supported memory attributes : "); + sep = ""; + for (i = 0; i < 8; i++) { + if (attrib & (1 << i)) { + p += sprintf(p, "%s%s", sep, mem_attrib[i]); + sep = ", "; + } } + p += sprintf(p, "\n"); } - p += sprintf(p, "\n"); if ((status = ia64_pal_vm_page_size(&tr_pages, &vw_pages)) !=0) { printk(KERN_ERR "ia64_pal_vm_page_size=%ld\n", status); - return 0; - } - - p += sprintf(p, - "\nTLB walker : %simplemented\n" - "Number of DTR : %d\n" - "Number of ITR : %d\n" - "TLB insertable page sizes : ", - vm_info_1.pal_vm_info_1_s.vw ? "" : "not ", - vm_info_1.pal_vm_info_1_s.max_dtr_entry+1, - vm_info_1.pal_vm_info_1_s.max_itr_entry+1); + } else { + p += sprintf(p, + "\nTLB walker : %simplemented\n" + "Number of DTR : %d\n" + "Number of ITR : %d\n" + "TLB insertable page sizes : ", + vm_info_1.pal_vm_info_1_s.vw ? "" : "not ", + vm_info_1.pal_vm_info_1_s.max_dtr_entry+1, + vm_info_1.pal_vm_info_1_s.max_itr_entry+1); - p = bitvector_process(p, tr_pages); - p += sprintf(p, "\nTLB purgeable page sizes : "); + p = bitvector_process(p, tr_pages); - p = bitvector_process(p, vw_pages); + p += sprintf(p, "\nTLB purgeable page sizes : "); + p = bitvector_process(p, vw_pages); + } if ((status=ia64_get_ptce(&ptce)) != 0) { printk(KERN_ERR "ia64_get_ptce=%ld\n", status); - return 0; - } - - p += sprintf(p, + } else { + p += sprintf(p, "\nPurge base address : 0x%016lx\n" "Purge outer loop count : %d\n" "Purge inner loop count : %d\n" "Purge outer loop stride : %d\n" "Purge inner loop stride : %d\n", - ptce.base, ptce.count[0], ptce.count[1], ptce.stride[0], ptce.stride[1]); + ptce.base, ptce.count[0], ptce.count[1], + ptce.stride[0], ptce.stride[1]); - p += sprintf(p, + p += sprintf(p, "TC Levels : %d\n" "Unique TC(s) : %d\n", vm_info_1.pal_vm_info_1_s.num_tc_levels, vm_info_1.pal_vm_info_1_s.max_unique_tcs); - for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) { - for (j=2; j>0 ; j--) { - tc_pages = 0; /* just in case */ + for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) { + for (j=2; j>0 ; j--) { + tc_pages = 0; /* just in case */ - /* even without unification, some levels may not be present */ - if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) { - continue; - } + /* even without unification, some levels may not be present */ + if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) { + continue; + } - p += sprintf(p, + p += sprintf(p, "\n%s Translation Cache Level %d:\n" "\tHash sets : %d\n" "\tAssociativity : %d\n" "\tNumber of entries : %d\n" "\tFlags : ", - cache_types[j+tc_info.tc_unified], i+1, tc_info.tc_num_sets, - tc_info.tc_associativity, tc_info.tc_num_entries); + cache_types[j+tc_info.tc_unified], i+1, + tc_info.tc_num_sets, + tc_info.tc_associativity, + tc_info.tc_num_entries); - if (tc_info.tc_pf) p += sprintf(p, "PreferredPageSizeOptimized "); - if (tc_info.tc_unified) p += sprintf(p, "Unified "); - if (tc_info.tc_reduce_tr) p += sprintf(p, "TCReduction"); + if (tc_info.tc_pf) + p += sprintf(p, "PreferredPageSizeOptimized "); + if (tc_info.tc_unified) + p += sprintf(p, "Unified "); + if (tc_info.tc_reduce_tr) + p += sprintf(p, "TCReduction"); - p += sprintf(p, "\n\tSupported page sizes: "); + p += sprintf(p, "\n\tSupported page sizes: "); - p = bitvector_process(p, tc_pages); + p = bitvector_process(p, tc_pages); - /* when unified date (j=2) is enough */ - if (tc_info.tc_unified) break; + /* when unified date (j=2) is enough */ + if (tc_info.tc_unified) + break; + } } } p += sprintf(p, "\n"); @@ -440,14 +445,14 @@ register_info(char *page) p += sprintf(p, "\n"); } - if (ia64_pal_rse_info(&phys_stacked, &hints) != 0) return 0; + if (ia64_pal_rse_info(&phys_stacked, &hints) == 0) { p += sprintf(p, "RSE stacked physical registers : %ld\n" "RSE load/store hints : %ld (%s)\n", phys_stacked, hints.ph_data, hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)"); - + } if (ia64_pal_debug_info(&iregs, &dregs)) return 0; -- GitLab From 6cf07a8cc86a0b471466c7fe45892f7ef434015b Mon Sep 17 00:00:00 2001 From: Peter Chubb <peterc@gelato.unsw.edu.au> Date: Tue, 23 Aug 2005 20:07:00 -0700 Subject: [PATCH 005/563] [IA64] Fix nasty VMLPT problem... I've solved the problem I was having with the simulator and not booting Debian. The problem is that the number of bits for the virtual linear array short-format VHPT (Virtually mapped linear page table, VMLPT for short) is being tested incorrectly. There are two problems: 1. The PAL call that should tell the kernel the size of the virtual address space isn't implemented for the simulator, so the kernel uses the default 50. This is addressed separately in dc90e95f310f4f821c905b2aec8e9449bb3270fa 2. In arch/ia64/mm/init.c there's code to calcualte the size of the VMLPT based on the number of implemented virtual address bits and the page size. It checks to see if the VMLPT base address overlaps the top of the mapped region, but this check doesn't allow for the address space hole, and in fact will never trigger. Here's an alternative test and panic, that I think is more accurate. Signed-off-by: Peter Chubb <peterc@gelato.unsw.edu.au> Signed-off-by: Tony Luck <tony.luck@intel.com> --- arch/ia64/mm/init.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 65f9958db9f03..1281c609ee98b 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -382,13 +382,22 @@ ia64_mmu_init (void *my_cpu_data) if (impl_va_bits < 51 || impl_va_bits > 61) panic("CPU has bogus IMPL_VA_MSB value of %lu!\n", impl_va_bits - 1); + /* + * mapped_space_bits - PAGE_SHIFT is the total number of ptes we need, + * which must fit into "vmlpt_bits - pte_bits" slots. Second half of + * the test makes sure that our mapped space doesn't overlap the + * unimplemented hole in the middle of the region. + */ + if ((mapped_space_bits - PAGE_SHIFT > vmlpt_bits - pte_bits) || + (mapped_space_bits > impl_va_bits - 1)) + panic("Cannot build a big enough virtual-linear page table" + " to cover mapped address space.\n" + " Try using a smaller page size.\n"); + /* place the VMLPT at the end of each page-table mapped region: */ pta = POW2(61) - POW2(vmlpt_bits); - if (POW2(mapped_space_bits) >= pta) - panic("mm/init: overlap between virtually mapped linear page table and " - "mapped kernel space!"); /* * Set the (virtually mapped linear) page table address. Bit * 8 selects between the short and long format, bits 2-7 the -- GitLab From a1cddb88920b915eaba10712ecfd0fc698b00a22 Mon Sep 17 00:00:00 2001 From: Jack Steiner <steiner@sgi.com> Date: Wed, 31 Aug 2005 08:05:00 -0700 Subject: [PATCH 006/563] [IA64-SGI] Add new vendor-specific SAL calls for: - notifying the PROM of specific features that are supported by the OS. This is used to enable PROM feature if and only if the corresponding feature is implemented in the OS - fetch feature sets that are supported by the current PROM. This allows the OS to selectively enable features when the PROM support is available. Signed-off-by: Jack Steiner <steiner@sgi.com> Signed-off-by: Tony Luck <tony.luck@intel.com> --- arch/ia64/sn/kernel/setup.c | 30 ++++++++------ include/asm-ia64/sn/sn_feature_sets.h | 57 +++++++++++++++++++++++++++ include/asm-ia64/sn/sn_sal.h | 36 ++++++++++++----- 3 files changed, 103 insertions(+), 20 deletions(-) create mode 100644 include/asm-ia64/sn/sn_feature_sets.h diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 7c7fe441d6237..981928f35a8c8 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -49,6 +49,7 @@ #include <asm/sn/clksupport.h> #include <asm/sn/sn_sal.h> #include <asm/sn/geo.h> +#include <asm/sn/sn_feature_sets.h> #include "xtalk/xwidgetdev.h" #include "xtalk/hubdev.h" #include <asm/sn/klconfig.h> @@ -99,6 +100,7 @@ EXPORT_SYMBOL(sn_region_size); int sn_prom_type; /* 0=hardware, 1=medusa/realprom, 2=medusa/fakeprom */ short physical_node_map[MAX_PHYSNODE_ID]; +static unsigned long sn_prom_features[MAX_PROM_FEATURE_SETS]; EXPORT_SYMBOL(physical_node_map); @@ -273,7 +275,10 @@ void __init sn_setup(char **cmdline_p) u32 version = sn_sal_rev(); extern void sn_cpu_init(void); - ia64_sn_plat_set_error_handling_features(); + ia64_sn_plat_set_error_handling_features(); // obsolete + ia64_sn_set_os_feature(OSF_MCA_SLV_TO_OS_INIT_SLV); + ia64_sn_set_os_feature(OSF_FEAT_LOG_SBES); + #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) /* @@ -316,16 +321,6 @@ void __init sn_setup(char **cmdline_p) printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF); - /* - * Confirm the SAL we're running on is recent enough... - */ - if (version < SN_SAL_MIN_VERSION) { - printk(KERN_ERR "This kernel needs SGI SAL version >= " - "%x.%02x\n", SN_SAL_MIN_VERSION >> 8, - SN_SAL_MIN_VERSION & 0x00FF); - panic("PROM version too old\n"); - } - master_nasid = boot_get_nasid(); status = @@ -481,6 +476,10 @@ void __init sn_cpu_init(void) if (nodepdaindr[0] == NULL) return; + for (i = 0; i < MAX_PROM_FEATURE_SETS; i++) + if (ia64_sn_get_prom_feature_set(i, &sn_prom_features[i]) != 0) + break; + cpuid = smp_processor_id(); cpuphyid = get_sapicid(); @@ -652,3 +651,12 @@ nasid_slice_to_cpuid(int nasid, int slice) return -1; } + +int sn_prom_feature_available(int id) +{ + if (id >= BITS_PER_LONG * MAX_PROM_FEATURE_SETS) + return 0; + return test_bit(id, sn_prom_features); +} +EXPORT_SYMBOL(sn_prom_feature_available); + diff --git a/include/asm-ia64/sn/sn_feature_sets.h b/include/asm-ia64/sn/sn_feature_sets.h new file mode 100644 index 0000000000000..e68a80853d5df --- /dev/null +++ b/include/asm-ia64/sn/sn_feature_sets.h @@ -0,0 +1,57 @@ +#ifndef _ASM_IA64_SN_FEATURE_SETS_H +#define _ASM_IA64_SN_FEATURE_SETS_H + +/* + * SN PROM Features + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. + */ + + +#include <asm/types.h> +#include <asm/bitops.h> + +/* --------------------- PROM Features -----------------------------*/ +extern int sn_prom_feature_available(int id); + +#define MAX_PROM_FEATURE_SETS 2 + +/* + * The following defines features that may or may not be supported by the + * current PROM. The OS uses sn_prom_feature_available(feature) to test for + * the presence of a PROM feature. Down rev (old) PROMs will always test + * "false" for new features. + * + * Use: + * if (sn_prom_feature_available(PRF_FEATURE_XXX)) + * ... + */ + +/* + * Example: feature XXX + */ +#define PRF_FEATURE_XXX 0 + + + +/* --------------------- OS Features -------------------------------*/ + +/* + * The following defines OS features that are optionally present in + * the operating system. + * During boot, PROM is notified of these features via a series of calls: + * + * ia64_sn_set_os_feature(feature1); + * + * Once enabled, a feature cannot be disabled. + * + * By default, features are disabled unless explicitly enabled. + */ +#define OSF_MCA_SLV_TO_OS_INIT_SLV 0 +#define OSF_FEAT_LOG_SBES 1 + +#endif /* _ASM_IA64_SN_FEATURE_SETS_H */ diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index 27976d2231865..231d0d04c3e8d 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -80,6 +80,9 @@ #define SN_SAL_BTE_RECOVER 0x02000061 #define SN_SAL_IOIF_GET_PCI_TOPOLOGY 0x02000062 +#define SN_SAL_GET_PROM_FEATURE_SET 0x02000065 +#define SN_SAL_SET_OS_FEATURE_SET 0x02000066 + /* * Service-specific constants */ @@ -118,8 +121,8 @@ /* * Error Handling Features */ -#define SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV 0x1 -#define SAL_ERR_FEAT_LOG_SBES 0x2 +#define SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV 0x1 // obsolete +#define SAL_ERR_FEAT_LOG_SBES 0x2 // obsolete #define SAL_ERR_FEAT_MFR_OVERRIDE 0x4 #define SAL_ERR_FEAT_SBE_THRESHOLD 0xffff0000 @@ -151,12 +154,6 @@ sn_sal_rev(void) return (u32)(systab->sal_b_rev_major << 8 | systab->sal_b_rev_minor); } -/* - * Specify the minimum PROM revsion required for this kernel. - * Note that they're stored in hex format... - */ -#define SN_SAL_MIN_VERSION 0x0404 - /* * Returns the master console nasid, if the call fails, return an illegal * value. @@ -336,7 +333,7 @@ ia64_sn_plat_cpei_handler(void) } /* - * Set Error Handling Features + * Set Error Handling Features (Obsolete) */ static inline u64 ia64_sn_plat_set_error_handling_features(void) @@ -1100,4 +1097,25 @@ ia64_sn_is_fake_prom(void) return (rv.status == 0); } +static inline int +ia64_sn_get_prom_feature_set(int set, unsigned long *feature_set) +{ + struct ia64_sal_retval rv; + + SAL_CALL_NOLOCK(rv, SN_SAL_GET_PROM_FEATURE_SET, set, 0, 0, 0, 0, 0, 0); + if (rv.status != 0) + return rv.status; + *feature_set = rv.v0; + return 0; +} + +static inline int +ia64_sn_set_os_feature(int feature) +{ + struct ia64_sal_retval rv; + + SAL_CALL_NOLOCK(rv, SN_SAL_SET_OS_FEATURE_SET, feature, 0, 0, 0, 0, 0, 0); + return rv.status; +} + #endif /* _ASM_IA64_SN_SN_SAL_H */ -- GitLab From 4f4b401bfaa97edbea41a1fcab794148e7ac0421 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp <shaggy@austin.ibm.com> Date: Thu, 1 Sep 2005 09:02:43 -0500 Subject: [PATCH 007/563] JFS: allow extended attributes to be set within a existing transaction Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com> --- fs/jfs/acl.c | 24 ++++++++++++------ fs/jfs/jfs_acl.h | 12 +++++++-- fs/jfs/jfs_xattr.h | 4 +-- fs/jfs/namei.c | 63 ++++++++++++++++++++++++++++++---------------- fs/jfs/xattr.c | 58 +++++++++++++++++++++++++++++------------- 5 files changed, 112 insertions(+), 49 deletions(-) diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index e892dab40c26a..461e4934ca7c2 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -23,6 +23,7 @@ #include <linux/quotaops.h> #include <linux/posix_acl_xattr.h> #include "jfs_incore.h" +#include "jfs_txnmgr.h" #include "jfs_xattr.h" #include "jfs_acl.h" @@ -75,7 +76,8 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type) return acl; } -static int jfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) +static int jfs_set_acl(tid_t tid, struct inode *inode, int type, + struct posix_acl *acl) { char *ea_name; struct jfs_inode_info *ji = JFS_IP(inode); @@ -110,7 +112,7 @@ static int jfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) if (rc < 0) goto out; } - rc = __jfs_setxattr(inode, ea_name, value, size, 0); + rc = __jfs_setxattr(tid, inode, ea_name, value, size, 0); out: kfree(value); @@ -143,7 +145,7 @@ int jfs_permission(struct inode *inode, int mask, struct nameidata *nd) return generic_permission(inode, mask, jfs_check_acl); } -int jfs_init_acl(struct inode *inode, struct inode *dir) +int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir) { struct posix_acl *acl = NULL; struct posix_acl *clone; @@ -159,7 +161,7 @@ int jfs_init_acl(struct inode *inode, struct inode *dir) if (acl) { if (S_ISDIR(inode->i_mode)) { - rc = jfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); + rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl); if (rc) goto cleanup; } @@ -173,7 +175,8 @@ int jfs_init_acl(struct inode *inode, struct inode *dir) if (rc >= 0) { inode->i_mode = mode; if (rc > 0) - rc = jfs_set_acl(inode, ACL_TYPE_ACCESS, clone); + rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, + clone); } posix_acl_release(clone); cleanup: @@ -202,8 +205,15 @@ static int jfs_acl_chmod(struct inode *inode) return -ENOMEM; rc = posix_acl_chmod_masq(clone, inode->i_mode); - if (!rc) - rc = jfs_set_acl(inode, ACL_TYPE_ACCESS, clone); + if (!rc) { + tid_t tid = txBegin(inode->i_sb, 0); + down(&JFS_IP(inode)->commit_sem); + rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, clone); + if (!rc) + rc = txCommit(tid, 1, &inode, 0); + txEnd(tid); + up(&JFS_IP(inode)->commit_sem); + } posix_acl_release(clone); return rc; diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h index a3acd3eec059c..a76293767c736 100644 --- a/fs/jfs/jfs_acl.h +++ b/fs/jfs/jfs_acl.h @@ -21,8 +21,16 @@ #ifdef CONFIG_JFS_POSIX_ACL int jfs_permission(struct inode *, int, struct nameidata *); -int jfs_init_acl(struct inode *, struct inode *); +int jfs_init_acl(tid_t, struct inode *, struct inode *); int jfs_setattr(struct dentry *, struct iattr *); -#endif /* CONFIG_JFS_POSIX_ACL */ +#else + +static inline int jfs_init_acl(tid_t tid, struct inode *inode, + struct inode *dir) +{ + return 0; +} + +#endif #endif /* _H_JFS_ACL */ diff --git a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h index a1052f3f0bee0..116a73ce3076e 100644 --- a/fs/jfs/jfs_xattr.h +++ b/fs/jfs/jfs_xattr.h @@ -52,8 +52,8 @@ struct jfs_ea_list { #define END_EALIST(ealist) \ ((struct jfs_ea *) (((char *) (ealist)) + EALIST_SIZE(ealist))) -extern int __jfs_setxattr(struct inode *, const char *, const void *, size_t, - int); +extern int __jfs_setxattr(tid_t, struct inode *, const char *, const void *, + size_t, int); extern int jfs_setxattr(struct dentry *, const char *, const void *, size_t, int); extern ssize_t __jfs_getxattr(struct inode *, const char *, void *, size_t); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 49ccde3937f97..f23f9c2aa5259 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -38,6 +38,24 @@ struct dentry_operations jfs_ci_dentry_operations; static s64 commitZeroLink(tid_t, struct inode *); +/* + * NAME: free_ea_wmap(inode) + * + * FUNCTION: free uncommitted extended attributes from working map + * + */ +static inline void free_ea_wmap(struct inode *inode) +{ + dxd_t *ea = &JFS_IP(inode)->ea; + + if (ea->flag & DXD_EXTENT) { + /* free EA pages from cache */ + invalidate_dxd_metapages(inode, *ea); + dbFree(inode, addressDXD(ea), lengthDXD(ea)); + } + ea->flag = 0; +} + /* * NAME: jfs_create(dip, dentry, mode) * @@ -89,8 +107,13 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); + rc = jfs_init_acl(tid, ip, dip); + if (rc) + goto out3; + if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { jfs_err("jfs_create: dtSearch returned %d", rc); + txAbort(tid, 0); goto out3; } @@ -139,6 +162,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); if (rc) { + free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else @@ -147,11 +171,6 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, out2: free_UCSname(&dname); -#ifdef CONFIG_JFS_POSIX_ACL - if (rc == 0) - jfs_init_acl(ip, dip); -#endif - out1: jfs_info("jfs_create: rc:%d", rc); @@ -216,8 +235,13 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); + rc = jfs_init_acl(tid, ip, dip); + if (rc) + goto out3; + if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { jfs_err("jfs_mkdir: dtSearch returned %d", rc); + txAbort(tid, 0); goto out3; } @@ -267,6 +291,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); if (rc) { + free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else @@ -275,10 +300,6 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) out2: free_UCSname(&dname); -#ifdef CONFIG_JFS_POSIX_ACL - if (rc == 0) - jfs_init_acl(ip, dip); -#endif out1: @@ -1000,6 +1021,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); if (rc) { + free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else @@ -1008,11 +1030,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, out2: free_UCSname(&dname); -#ifdef CONFIG_JFS_POSIX_ACL - if (rc == 0) - jfs_init_acl(ip, dip); -#endif - out1: jfs_info("jfs_symlink: rc:%d", rc); return rc; @@ -1328,17 +1345,25 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, down(&JFS_IP(dir)->commit_sem); down(&JFS_IP(ip)->commit_sem); - if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) + rc = jfs_init_acl(tid, ip, dir); + if (rc) goto out3; + if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) { + txAbort(tid, 0); + goto out3; + } + tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; tblk->ino = ip->i_ino; tblk->u.ixpxd = JFS_IP(ip)->ixpxd; ino = ip->i_ino; - if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) + if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) { + txAbort(tid, 0); goto out3; + } ip->i_op = &jfs_file_inode_operations; jfs_ip->dev = new_encode_dev(rdev); @@ -1360,6 +1385,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, up(&JFS_IP(ip)->commit_sem); up(&JFS_IP(dir)->commit_sem); if (rc) { + free_ea_wmap(ip); ip->i_nlink = 0; iput(ip); } else @@ -1368,11 +1394,6 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, out1: free_UCSname(&dname); -#ifdef CONFIG_JFS_POSIX_ACL - if (rc == 0) - jfs_init_acl(ip, dir); -#endif - out: jfs_info("jfs_mknod: returning %d", rc); return rc; diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 554ec739e49b9..35674b2a0e6c5 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -633,12 +633,12 @@ static void ea_release(struct inode *inode, struct ea_buffer *ea_buf) } } -static int ea_put(struct inode *inode, struct ea_buffer *ea_buf, int new_size) +static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf, + int new_size) { struct jfs_inode_info *ji = JFS_IP(inode); unsigned long old_blocks, new_blocks; int rc = 0; - tid_t tid; if (new_size == 0) { ea_release(inode, ea_buf); @@ -664,9 +664,6 @@ static int ea_put(struct inode *inode, struct ea_buffer *ea_buf, int new_size) if (rc) return rc; - tid = txBegin(inode->i_sb, 0); - down(&ji->commit_sem); - old_blocks = new_blocks = 0; if (ji->ea.flag & DXD_EXTENT) { @@ -695,11 +692,8 @@ static int ea_put(struct inode *inode, struct ea_buffer *ea_buf, int new_size) DQUOT_FREE_BLOCK(inode, old_blocks); inode->i_ctime = CURRENT_TIME; - rc = txCommit(tid, 1, &inode, 0); - txEnd(tid); - up(&ji->commit_sem); - return rc; + return 0; } /* @@ -810,8 +804,8 @@ static int can_set_xattr(struct inode *inode, const char *name, return permission(inode, MAY_WRITE, NULL); } -int __jfs_setxattr(struct inode *inode, const char *name, const void *value, - size_t value_len, int flags) +int __jfs_setxattr(tid_t tid, struct inode *inode, const char *name, + const void *value, size_t value_len, int flags) { struct jfs_ea_list *ealist; struct jfs_ea *ea, *old_ea = NULL, *next_ea = NULL; @@ -825,9 +819,6 @@ int __jfs_setxattr(struct inode *inode, const char *name, const void *value, int rc; int length; - if ((rc = can_set_xattr(inode, name, value, value_len))) - return rc; - if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1, GFP_KERNEL); @@ -939,7 +930,7 @@ int __jfs_setxattr(struct inode *inode, const char *name, const void *value, ealist->size = cpu_to_le32(new_size); - rc = ea_put(inode, &ea_buf, new_size); + rc = ea_put(tid, inode, &ea_buf, new_size); goto out; release: @@ -955,12 +946,29 @@ int __jfs_setxattr(struct inode *inode, const char *name, const void *value, int jfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t value_len, int flags) { + struct inode *inode = dentry->d_inode; + struct jfs_inode_info *ji = JFS_IP(inode); + int rc; + tid_t tid; + + if ((rc = can_set_xattr(inode, name, value, value_len))) + return rc; + if (value == NULL) { /* empty EA, do not remove */ value = ""; value_len = 0; } - return __jfs_setxattr(dentry->d_inode, name, value, value_len, flags); + tid = txBegin(inode->i_sb, 0); + down(&ji->commit_sem); + rc = __jfs_setxattr(tid, dentry->d_inode, name, value, value_len, + flags); + if (!rc) + rc = txCommit(tid, 1, &inode, 0); + txEnd(tid); + up(&ji->commit_sem); + + return rc; } static int can_get_xattr(struct inode *inode, const char *name) @@ -1122,5 +1130,21 @@ ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size) int jfs_removexattr(struct dentry *dentry, const char *name) { - return __jfs_setxattr(dentry->d_inode, name, NULL, 0, XATTR_REPLACE); + struct inode *inode = dentry->d_inode; + struct jfs_inode_info *ji = JFS_IP(inode); + int rc; + tid_t tid; + + if ((rc = can_set_xattr(inode, name, NULL, 0))) + return rc; + + tid = txBegin(inode->i_sb, 0); + down(&ji->commit_sem); + rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE); + if (!rc) + rc = txCommit(tid, 1, &inode, 0); + txEnd(tid); + up(&ji->commit_sem); + + return rc; } -- GitLab From 1d15b10f95d4c4295a0f2288c7be7b6a005490da Mon Sep 17 00:00:00 2001 From: Dave Kleikamp <shaggy@austin.ibm.com> Date: Thu, 1 Sep 2005 09:05:39 -0500 Subject: [PATCH 008/563] JFS: Implement jfs_init_security This atomically initializes the security xattr when an object is created Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com> --- fs/jfs/jfs_xattr.h | 10 ++++++++++ fs/jfs/namei.c | 22 ++++++++++++++++++++++ fs/jfs/xattr.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h index 116a73ce3076e..25e9990bccd1b 100644 --- a/fs/jfs/jfs_xattr.h +++ b/fs/jfs/jfs_xattr.h @@ -61,4 +61,14 @@ extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t jfs_listxattr(struct dentry *, char *, size_t); extern int jfs_removexattr(struct dentry *, const char *); +#ifdef CONFIG_JFS_SECURITY +extern int jfs_init_security(tid_t, struct inode *, struct inode *); +#else +static inline int jfs_init_security(tid_t tid, struct inode *inode, + struct inode *dir) +{ + return 0; +} +#endif + #endif /* H_JFS_XATTR */ diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index f23f9c2aa5259..1abe7343f9204 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -111,6 +111,12 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, if (rc) goto out3; + rc = jfs_init_security(tid, ip, dip); + if (rc) { + txAbort(tid, 0); + goto out3; + } + if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { jfs_err("jfs_create: dtSearch returned %d", rc); txAbort(tid, 0); @@ -239,6 +245,12 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) if (rc) goto out3; + rc = jfs_init_security(tid, ip, dip); + if (rc) { + txAbort(tid, 0); + goto out3; + } + if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) { jfs_err("jfs_mkdir: dtSearch returned %d", rc); txAbort(tid, 0); @@ -906,6 +918,10 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(ip)->commit_sem); + rc = jfs_init_security(tid, ip, dip); + if (rc) + goto out3; + tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_CREATE; tblk->ino = ip->i_ino; @@ -1349,6 +1365,12 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, if (rc) goto out3; + rc = jfs_init_security(tid, ip, dir); + if (rc) { + txAbort(tid, 0); + goto out3; + } + if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) { txAbort(tid, 0); goto out3; diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 35674b2a0e6c5..23aa5066b5a43 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -21,6 +21,7 @@ #include <linux/xattr.h> #include <linux/posix_acl_xattr.h> #include <linux/quotaops.h> +#include <linux/security.h> #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_dmap.h" @@ -1148,3 +1149,38 @@ int jfs_removexattr(struct dentry *dentry, const char *name) return rc; } + +#ifdef CONFIG_JFS_SECURITY +int jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir) +{ + int rc; + size_t len; + void *value; + char *suffix; + char *name; + + rc = security_inode_init_security(inode, dir, &suffix, &value, &len); + if (rc) { + if (rc == -EOPNOTSUPP) + return 0; + return rc; + } + name = kmalloc(XATTR_SECURITY_PREFIX_LEN + 1 + strlen(suffix), + GFP_NOFS); + if (!name) { + rc = -ENOMEM; + goto kmalloc_failed; + } + strcpy(name, XATTR_SECURITY_PREFIX); + strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix); + + rc = __jfs_setxattr(tid, inode, name, value, len, 0); + + kfree(name); +kmalloc_failed: + kfree(suffix); + kfree(value); + + return rc; +} +#endif -- GitLab From cfe9e88866fe892f4f71bf132c64ec8bd5256e5e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov <dtor_core@ameritech.net> Date: Sun, 4 Sep 2005 01:40:20 -0500 Subject: [PATCH 009/563] Input: rework psmouse attributes to reduce module size Rearrange attribute code to use generic show and set handlers instead of replicating them for every attribute; switch to using attribute_group instead of creating all attributes manually. All this saves about 4K. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/mouse/logips2pp.c | 12 +- drivers/input/mouse/psmouse-base.c | 117 ++++++++++-------- drivers/input/mouse/psmouse.h | 51 +++++--- drivers/input/mouse/trackpoint.c | 183 +++++++++++++++-------------- 4 files changed, 200 insertions(+), 163 deletions(-) diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 48d2b20d26429..e65c2798a4913 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -150,12 +150,12 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscr ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); } -static ssize_t psmouse_attr_show_smartscroll(struct psmouse *psmouse, char *buf) +static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, void *data, char *buf) { return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0); } -static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char *buf, size_t count) +static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count) { unsigned long value; char *rest; @@ -169,7 +169,8 @@ static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char return count; } -PSMOUSE_DEFINE_ATTR(smartscroll); +PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL, + ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll); /* * Support 800 dpi resolution _only_ if the user wants it (there are good @@ -194,7 +195,7 @@ static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolutio static void ps2pp_disconnect(struct psmouse *psmouse) { - device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll); + device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); } static struct ps2pp_info *get_model_info(unsigned char model) @@ -379,7 +380,8 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) psmouse->set_resolution = ps2pp_set_resolution; psmouse->disconnect = ps2pp_disconnect; - device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll); + device_create_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_smartscroll.dattr); } } diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index b3508276785f0..0830c6e13ef63 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -58,10 +58,30 @@ static unsigned int psmouse_resetafter; module_param_named(resetafter, psmouse_resetafter, uint, 0644); MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); -PSMOUSE_DEFINE_ATTR(protocol); -PSMOUSE_DEFINE_ATTR(rate); -PSMOUSE_DEFINE_ATTR(resolution); -PSMOUSE_DEFINE_ATTR(resetafter); +PSMOUSE_DEFINE_ATTR(protocol, S_IWUSR | S_IRUGO, + NULL, + psmouse_attr_show_protocol, psmouse_attr_set_protocol); +PSMOUSE_DEFINE_ATTR(rate, S_IWUSR | S_IRUGO, + (void *) offsetof(struct psmouse, rate), + psmouse_show_int_attr, psmouse_attr_set_rate); +PSMOUSE_DEFINE_ATTR(resolution, S_IWUSR | S_IRUGO, + (void *) offsetof(struct psmouse, resolution), + psmouse_show_int_attr, psmouse_attr_set_resolution); +PSMOUSE_DEFINE_ATTR(resetafter, S_IWUSR | S_IRUGO, + (void *) offsetof(struct psmouse, resetafter), + psmouse_show_int_attr, psmouse_set_int_attr); + +static struct attribute *psmouse_attributes[] = { + &psmouse_attr_protocol.dattr.attr, + &psmouse_attr_rate.dattr.attr, + &psmouse_attr_resolution.dattr.attr, + &psmouse_attr_resetafter.dattr.attr, + NULL +}; + +static struct attribute_group psmouse_attribute_group = { + .attrs = psmouse_attributes, +}; __obsolete_setup("psmouse_noext"); __obsolete_setup("psmouse_resolution="); @@ -800,10 +820,7 @@ static void psmouse_disconnect(struct serio *serio) psmouse = serio_get_drvdata(serio); - device_remove_file(&serio->dev, &psmouse_attr_protocol); - device_remove_file(&serio->dev, &psmouse_attr_rate); - device_remove_file(&serio->dev, &psmouse_attr_resolution); - device_remove_file(&serio->dev, &psmouse_attr_resetafter); + sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group); down(&psmouse_sem); @@ -940,10 +957,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) if (parent && parent->pt_activate) parent->pt_activate(parent); - device_create_file(&serio->dev, &psmouse_attr_protocol); - device_create_file(&serio->dev, &psmouse_attr_rate); - device_create_file(&serio->dev, &psmouse_attr_resolution); - device_create_file(&serio->dev, &psmouse_attr_resetafter); + sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group); psmouse_activate(psmouse); @@ -1040,10 +1054,12 @@ static struct serio_driver psmouse_drv = { .cleanup = psmouse_cleanup, }; -ssize_t psmouse_attr_show_helper(struct device *dev, char *buf, - ssize_t (*handler)(struct psmouse *, char *)) +ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *devattr, + char *buf) { struct serio *serio = to_serio_port(dev); + struct psmouse_attribute *attr = to_psmouse_attr(devattr); + struct psmouse *psmouse; int retval; retval = serio_pin_driver(serio); @@ -1055,19 +1071,21 @@ ssize_t psmouse_attr_show_helper(struct device *dev, char *buf, goto out; } - retval = handler(serio_get_drvdata(serio), buf); + psmouse = serio_get_drvdata(serio); + + retval = attr->show(psmouse, attr->data, buf); out: serio_unpin_driver(serio); return retval; } -ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count, - ssize_t (*handler)(struct psmouse *, const char *, size_t)) +ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { struct serio *serio = to_serio_port(dev); - struct psmouse *psmouse = serio_get_drvdata(serio); - struct psmouse *parent = NULL; + struct psmouse_attribute *attr = to_psmouse_attr(devattr); + struct psmouse *psmouse, *parent = NULL; int retval; retval = serio_pin_driver(serio); @@ -1083,6 +1101,8 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun if (retval) goto out_unpin; + psmouse = serio_get_drvdata(serio); + if (psmouse->state == PSMOUSE_IGNORE) { retval = -ENODEV; goto out_up; @@ -1095,7 +1115,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun psmouse_deactivate(psmouse); - retval = handler(psmouse, buf, count); + retval = attr->set(psmouse, attr->data, buf, count); if (retval != -ENODEV) psmouse_activate(psmouse); @@ -1110,12 +1130,34 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun return retval; } -static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf) +static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char *buf) +{ + unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset); + + return sprintf(buf, "%lu\n", *field); +} + +static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count) +{ + unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset); + unsigned long value; + char *rest; + + value = simple_strtoul(buf, &rest, 10); + if (*rest) + return -EINVAL; + + *field = value; + + return count; +} + +static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, void *data, char *buf) { return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name); } -static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count) +static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, const char *buf, size_t count) { struct serio *serio = psmouse->ps2dev.serio; struct psmouse *parent = NULL; @@ -1179,12 +1221,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *bu return count; } -static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf) -{ - return sprintf(buf, "%d\n", psmouse->rate); -} - -static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, size_t count) +static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count) { unsigned long value; char *rest; @@ -1197,12 +1234,7 @@ static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, s return count; } -static ssize_t psmouse_attr_show_resolution(struct psmouse *psmouse, char *buf) -{ - return sprintf(buf, "%d\n", psmouse->resolution); -} - -static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char *buf, size_t count) +static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count) { unsigned long value; char *rest; @@ -1215,23 +1247,6 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char * return count; } -static ssize_t psmouse_attr_show_resetafter(struct psmouse *psmouse, char *buf) -{ - return sprintf(buf, "%d\n", psmouse->resetafter); -} - -static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *buf, size_t count) -{ - unsigned long value; - char *rest; - - value = simple_strtoul(buf, &rest, 10); - if (*rest) - return -EINVAL; - - psmouse->resetafter = value; - return count; -} static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) { diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index e312a6b416811..45d2bd774f00f 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -86,24 +86,37 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); int psmouse_reset(struct psmouse *psmouse); void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); -ssize_t psmouse_attr_show_helper(struct device *dev, char *buf, - ssize_t (*handler)(struct psmouse *, char *)); -ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count, - ssize_t (*handler)(struct psmouse *, const char *, size_t)); - -#define PSMOUSE_DEFINE_ATTR(_name) \ -static ssize_t psmouse_attr_show_##_name(struct psmouse *, char *); \ -static ssize_t psmouse_attr_set_##_name(struct psmouse *, const char *, size_t);\ -static ssize_t psmouse_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \ -{ \ - return psmouse_attr_show_helper(d, b, psmouse_attr_show_##_name); \ -} \ -static ssize_t psmouse_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s)\ -{ \ - return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name); \ -} \ -static struct device_attribute psmouse_attr_##_name = \ - __ATTR(_name, S_IWUSR | S_IRUGO, \ - psmouse_do_show_##_name, psmouse_do_set_##_name); + +struct psmouse_attribute { + struct device_attribute dattr; + void *data; + ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf); + ssize_t (*set)(struct psmouse *psmouse, void *data, + const char *buf, size_t count); +}; +#define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr) + +ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *attr, + char *buf); +ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); + +#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \ +static ssize_t _show(struct psmouse *, void *data, char *); \ +static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \ +static struct psmouse_attribute psmouse_attr_##_name = { \ + .dattr = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = _mode, \ + .owner = THIS_MODULE, \ + }, \ + .show = psmouse_attr_show_helper, \ + .store = psmouse_attr_set_helper, \ + }, \ + .data = _data, \ + .show = _show, \ + .set = _set, \ +} #endif /* _PSMOUSE_H */ diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index aee3b24a91026..b4898d8a68e21 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -19,54 +19,6 @@ #include "psmouse.h" #include "trackpoint.h" -PSMOUSE_DEFINE_ATTR(sensitivity); -PSMOUSE_DEFINE_ATTR(speed); -PSMOUSE_DEFINE_ATTR(inertia); -PSMOUSE_DEFINE_ATTR(reach); -PSMOUSE_DEFINE_ATTR(draghys); -PSMOUSE_DEFINE_ATTR(mindrag); -PSMOUSE_DEFINE_ATTR(thresh); -PSMOUSE_DEFINE_ATTR(upthresh); -PSMOUSE_DEFINE_ATTR(ztime); -PSMOUSE_DEFINE_ATTR(jenks); -PSMOUSE_DEFINE_ATTR(press_to_select); -PSMOUSE_DEFINE_ATTR(skipback); -PSMOUSE_DEFINE_ATTR(ext_dev); - -#define MAKE_ATTR_READ(_item) \ - static ssize_t psmouse_attr_show_##_item(struct psmouse *psmouse, char *buf) \ - { \ - struct trackpoint_data *tp = psmouse->private; \ - return sprintf(buf, "%lu\n", (unsigned long)tp->_item); \ - } - -#define MAKE_ATTR_WRITE(_item, command) \ - static ssize_t psmouse_attr_set_##_item(struct psmouse *psmouse, const char *buf, size_t count) \ - { \ - char *rest; \ - unsigned long value; \ - struct trackpoint_data *tp = psmouse->private; \ - value = simple_strtoul(buf, &rest, 10); \ - if (*rest) \ - return -EINVAL; \ - tp->_item = value; \ - trackpoint_write(&psmouse->ps2dev, command, tp->_item); \ - return count; \ - } - -#define MAKE_ATTR_TOGGLE(_item, command, mask) \ - static ssize_t psmouse_attr_set_##_item(struct psmouse *psmouse, const char *buf, size_t count) \ - { \ - unsigned char toggle; \ - struct trackpoint_data *tp = psmouse->private; \ - toggle = (buf[0] == '1') ? 1 : 0; \ - if (toggle != tp->_item) { \ - tp->_item = toggle; \ - trackpoint_toggle_bit(&psmouse->ps2dev, command, mask); \ - } \ - return count; \ - } - /* * Device IO: read, write and toggle bit */ @@ -108,59 +60,114 @@ static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsig return 0; } -MAKE_ATTR_WRITE(sensitivity, TP_SENS); -MAKE_ATTR_READ(sensitivity); - -MAKE_ATTR_WRITE(speed, TP_SPEED); -MAKE_ATTR_READ(speed); -MAKE_ATTR_WRITE(inertia, TP_INERTIA); -MAKE_ATTR_READ(inertia); +/* + * Trackpoint-specific attributes + */ +struct trackpoint_attr_data { + size_t field_offset; + unsigned char command; + unsigned char mask; +}; -MAKE_ATTR_WRITE(reach, TP_REACH); -MAKE_ATTR_READ(reach); +static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf) +{ + struct trackpoint_data *tp = psmouse->private; + struct trackpoint_attr_data *attr = data; + unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); -MAKE_ATTR_WRITE(draghys, TP_DRAGHYS); -MAKE_ATTR_READ(draghys); + return sprintf(buf, "%u\n", *field); +} -MAKE_ATTR_WRITE(mindrag, TP_MINDRAG); -MAKE_ATTR_READ(mindrag); +static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct trackpoint_data *tp = psmouse->private; + struct trackpoint_attr_data *attr = data; + unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); + unsigned long value; + char *rest; -MAKE_ATTR_WRITE(thresh, TP_THRESH); -MAKE_ATTR_READ(thresh); + value = simple_strtoul(buf, &rest, 10); + if (*rest || value > 255) + return -EINVAL; -MAKE_ATTR_WRITE(upthresh, TP_UP_THRESH); -MAKE_ATTR_READ(upthresh); + *field = value; + trackpoint_write(&psmouse->ps2dev, attr->command, value); -MAKE_ATTR_WRITE(ztime, TP_Z_TIME); -MAKE_ATTR_READ(ztime); + return count; +} -MAKE_ATTR_WRITE(jenks, TP_JENKS_CURV); -MAKE_ATTR_READ(jenks); +#define TRACKPOINT_INT_ATTR(_name, _command) \ + static struct trackpoint_attr_data trackpoint_attr_##_name = { \ + .field_offset = offsetof(struct trackpoint_data, _name), \ + .command = _command, \ + }; \ + PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ + &trackpoint_attr_##_name, \ + trackpoint_show_int_attr, trackpoint_set_int_attr) + +static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct trackpoint_data *tp = psmouse->private; + struct trackpoint_attr_data *attr = data; + unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); + unsigned long value; + char *rest; + + value = simple_strtoul(buf, &rest, 10); + if (*rest || value > 1) + return -EINVAL; + + if (*field != value) { + *field = value; + trackpoint_toggle_bit(&psmouse->ps2dev, attr->command, attr->mask); + } -MAKE_ATTR_TOGGLE(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON); -MAKE_ATTR_READ(press_to_select); + return count; +} -MAKE_ATTR_TOGGLE(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); -MAKE_ATTR_READ(skipback); -MAKE_ATTR_TOGGLE(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); -MAKE_ATTR_READ(ext_dev); +#define TRACKPOINT_BIT_ATTR(_name, _command, _mask) \ + static struct trackpoint_attr_data trackpoint_attr_##_name = { \ + .field_offset = offsetof(struct trackpoint_data, _name), \ + .command = _command, \ + .mask = _mask, \ + }; \ + PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ + &trackpoint_attr_##_name, \ + trackpoint_show_int_attr, trackpoint_set_bit_attr) + +TRACKPOINT_INT_ATTR(sensitivity, TP_SENS); +TRACKPOINT_INT_ATTR(speed, TP_SPEED); +TRACKPOINT_INT_ATTR(inertia, TP_INERTIA); +TRACKPOINT_INT_ATTR(reach, TP_REACH); +TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS); +TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG); +TRACKPOINT_INT_ATTR(thresh, TP_THRESH); +TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH); +TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME); +TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV); + +TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON); +TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); +TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); static struct attribute *trackpoint_attrs[] = { - &psmouse_attr_sensitivity.attr, - &psmouse_attr_speed.attr, - &psmouse_attr_inertia.attr, - &psmouse_attr_reach.attr, - &psmouse_attr_draghys.attr, - &psmouse_attr_mindrag.attr, - &psmouse_attr_thresh.attr, - &psmouse_attr_upthresh.attr, - &psmouse_attr_ztime.attr, - &psmouse_attr_jenks.attr, - &psmouse_attr_press_to_select.attr, - &psmouse_attr_skipback.attr, - &psmouse_attr_ext_dev.attr, + &psmouse_attr_sensitivity.dattr.attr, + &psmouse_attr_speed.dattr.attr, + &psmouse_attr_inertia.dattr.attr, + &psmouse_attr_reach.dattr.attr, + &psmouse_attr_draghys.dattr.attr, + &psmouse_attr_mindrag.dattr.attr, + &psmouse_attr_thresh.dattr.attr, + &psmouse_attr_upthresh.dattr.attr, + &psmouse_attr_ztime.dattr.attr, + &psmouse_attr_jenks.dattr.attr, + &psmouse_attr_press_to_select.dattr.attr, + &psmouse_attr_skipback.dattr.attr, + &psmouse_attr_ext_dev.dattr.attr, NULL }; -- GitLab From e6c047b98bbd09473c586744c681e877ebf954ff Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Sun, 4 Sep 2005 01:40:43 -0500 Subject: [PATCH 010/563] Input: ALPS - fix wheel decoding Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/mouse/alps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 0d68e5e0182ae..b20783f9748ad 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -170,7 +170,7 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) input_report_key(dev, BTN_TOOL_FINGER, z > 0); if (priv->i->flags & ALPS_WHEEL) - input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08)); + input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { input_report_key(dev, BTN_FORWARD, forward); -- GitLab From d2b5ffca73594e4046f405e3ef2438ce41f76fb2 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Sun, 4 Sep 2005 01:40:55 -0500 Subject: [PATCH 011/563] Input: psmouse - add new Logitech wheel mouse model Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/mouse/logips2pp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index e65c2798a4913..7df96525222e5 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -223,6 +223,7 @@ static struct ps2pp_info *get_model_info(unsigned char model) { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, + { 86, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 96, 0, 0 }, { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL }, -- GitLab From 4cee99564db7f65a6f88e4b752da52768cde3802 Mon Sep 17 00:00:00 2001 From: Ian Campbell <ijc@hellion.org.uk> Date: Sun, 4 Sep 2005 01:41:14 -0500 Subject: [PATCH 012/563] Input: fix checking whether new keycode fits size-wise When dev->keycodesize == sizeof(int) the old code produces incorrect result. Signed-off-by: Ian Campbell <ijc@hellion.org.uk> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/char/keyboard.c | 2 +- drivers/input/evdev.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 523fd3c8bbaa7..1ddaabeb8ef89 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -200,7 +200,7 @@ int setkeycode(unsigned int scancode, unsigned int keycode) return -EINVAL; if (keycode < 0 || keycode > KEY_MAX) return -EINVAL; - if (keycode >> (dev->keycodesize * 8)) + if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) return -EINVAL; oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode); diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 20e3a165989fb..3a8314bb79022 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -320,7 +320,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; if (get_user(v, ip + 1)) return -EFAULT; if (v < 0 || v > KEY_MAX) return -EINVAL; - if (v >> (dev->keycodesize * 8)) return -EINVAL; + if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) return -EINVAL; u = SET_INPUT_KEYCODE(dev, t, v); clear_bit(u, dev->keybit); set_bit(v, dev->keybit); -- GitLab From 0854e52d86080c1043bc8988daef2ebda4775f64 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov <dtor_core@ameritech.net> Date: Sun, 4 Sep 2005 01:41:27 -0500 Subject: [PATCH 013/563] Input: i8042 - clean up initialization code; abort if we can't create all ports. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/serio/i8042.c | 178 ++++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 78 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 708a1d3beab97..f0d9c5f9cc368 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -338,10 +338,10 @@ static int i8042_open(struct serio *serio) return 0; -activate_fail: + activate_fail: free_irq(port->irq, i8042_request_irq_cookie); -irq_fail: + irq_fail: serio_unregister_port_delayed(serio); return -1; @@ -485,7 +485,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) serio_interrupt(port->serio, data, dfl, regs); ret = 1; -out: + out: return IRQ_RETVAL(ret); } @@ -552,7 +552,7 @@ static int i8042_enable_mux_ports(void) * Enable all muxed ports. */ - for (i = 0; i < 4; i++) { + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { i8042_command(¶m, I8042_CMD_MUX_PFX + i); i8042_command(¶m, I8042_CMD_AUX_ENABLE); } @@ -682,7 +682,7 @@ static int __init i8042_port_register(struct i8042_port *port) kfree(port->serio); port->serio = NULL; i8042_ctr |= port->disable; - return -1; + return -EIO; } printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n", @@ -977,80 +977,83 @@ static struct device_driver i8042_driver = { .shutdown = i8042_shutdown, }; -static void __init i8042_create_kbd_port(void) +static int __init i8042_create_kbd_port(void) { struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (serio) { - memset(serio, 0, sizeof(struct serio)); - serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; - serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; - serio->open = i8042_open; - serio->close = i8042_close; - serio->start = i8042_start; - serio->stop = i8042_stop; - serio->port_data = port; - serio->dev.parent = &i8042_platform_device->dev; - strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); - strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); - - port->serio = serio; - i8042_port_register(port); - } + serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; + serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->start = i8042_start; + serio->stop = i8042_stop; + serio->port_data = port; + serio->dev.parent = &i8042_platform_device->dev; + strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); + + port->serio = serio; + + return i8042_port_register(port); } -static void __init i8042_create_aux_port(void) +static int __init i8042_create_aux_port(void) { struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO]; - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (serio) { - memset(serio, 0, sizeof(struct serio)); - serio->id.type = SERIO_8042; - serio->write = i8042_aux_write; - serio->open = i8042_open; - serio->close = i8042_close; - serio->start = i8042_start; - serio->stop = i8042_stop; - serio->port_data = port; - serio->dev.parent = &i8042_platform_device->dev; - strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); - strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); - - port->serio = serio; - i8042_port_register(port); - } + serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + serio->id.type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->start = i8042_start; + serio->stop = i8042_stop; + serio->port_data = port; + serio->dev.parent = &i8042_platform_device->dev; + strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); + + port->serio = serio; + + return i8042_port_register(port); } -static void __init i8042_create_mux_port(int index) +static int __init i8042_create_mux_port(int index) { struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index]; - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (serio) { - memset(serio, 0, sizeof(struct serio)); - serio->id.type = SERIO_8042; - serio->write = i8042_aux_write; - serio->open = i8042_open; - serio->close = i8042_close; - serio->start = i8042_start; - serio->stop = i8042_stop; - serio->port_data = port; - serio->dev.parent = &i8042_platform_device->dev; - snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); - snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); - - *port = i8042_ports[I8042_AUX_PORT_NO]; - port->exists = 0; - snprintf(port->name, sizeof(port->name), "AUX%d", index); - port->mux = index; - port->serio = serio; - i8042_port_register(port); - } + serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + serio->id.type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->start = i8042_start; + serio->stop = i8042_stop; + serio->port_data = port; + serio->dev.parent = &i8042_platform_device->dev; + snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); + snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); + + *port = i8042_ports[I8042_AUX_PORT_NO]; + port->exists = 0; + snprintf(port->name, sizeof(port->name), "AUX%d", index); + port->mux = index; + port->serio = serio; + + return i8042_port_register(port); } static int __init i8042_init(void) @@ -1070,36 +1073,55 @@ static int __init i8042_init(void) i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ; if (i8042_controller_init()) { - i8042_platform_exit(); - return -ENODEV; + err = -ENODEV; + goto err_platform_exit; } err = driver_register(&i8042_driver); - if (err) { - i8042_platform_exit(); - return err; - } + if (err) + goto err_controller_cleanup; i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0); if (IS_ERR(i8042_platform_device)) { - driver_unregister(&i8042_driver); - i8042_platform_exit(); - return PTR_ERR(i8042_platform_device); + err = PTR_ERR(i8042_platform_device); + goto err_unregister_driver; } if (!i8042_noaux && !i8042_check_aux()) { - if (!i8042_nomux && !i8042_check_mux()) - for (i = 0; i < I8042_NUM_MUX_PORTS; i++) - i8042_create_mux_port(i); - else - i8042_create_aux_port(); + if (!i8042_nomux && !i8042_check_mux()) { + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { + err = i8042_create_mux_port(i); + if (err) + goto err_unregister_ports; + } + } else { + err = i8042_create_aux_port(); + if (err) + goto err_unregister_ports; + } } - i8042_create_kbd_port(); + err = i8042_create_kbd_port(); + if (err) + goto err_unregister_ports; mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); return 0; + + err_unregister_ports: + for (i = 0; i < I8042_NUM_PORTS; i++) + if (i8042_ports[i].serio) + serio_unregister_port(i8042_ports[i].serio); + platform_device_unregister(i8042_platform_device); + err_unregister_driver: + driver_unregister(&i8042_driver); + err_controller_cleanup: + i8042_controller_cleanup(); + err_platform_exit: + i8042_platform_exit(); + + return err; } static void __exit i8042_exit(void) -- GitLab From 8d5987a6e17fa36776a0c9964db0f24c3d070862 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov <dtor_core@ameritech.net> Date: Sun, 4 Sep 2005 01:41:38 -0500 Subject: [PATCH 014/563] Input: make i8042_platform_init return 'real' error code Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/serio/i8042-io.h | 6 +++--- drivers/input/serio/i8042-ip22io.h | 2 +- drivers/input/serio/i8042-jazzio.h | 2 +- drivers/input/serio/i8042-sparcio.h | 12 ++++++------ drivers/input/serio/i8042-x86ia64io.h | 22 ++++++++++++---------- drivers/input/serio/i8042.c | 5 +++-- 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index c9e633d21d903..9a92216442501 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -69,16 +69,16 @@ static inline int i8042_platform_init(void) */ #if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC64) if (!request_region(I8042_DATA_REG, 16, "i8042")) - return -1; + return -EBUSY; #endif i8042_reset = 1; #if defined(CONFIG_PPC64) if (check_legacy_ioport(I8042_DATA_REG)) - return -1; + return -EBUSY; if (!request_region(I8042_DATA_REG, 16, "i8042")) - return -1; + return -EBUSY; #endif return 0; } diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h index 863b9c95fbb86..ee1ad27d6ed06 100644 --- a/drivers/input/serio/i8042-ip22io.h +++ b/drivers/input/serio/i8042-ip22io.h @@ -58,7 +58,7 @@ static inline int i8042_platform_init(void) #if 0 /* XXX sgi_kh is a virtual address */ if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042")) - return 1; + return -EBUSY; #endif i8042_reset = 1; diff --git a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h index 5c20ab131488e..13fd7108eb283 100644 --- a/drivers/input/serio/i8042-jazzio.h +++ b/drivers/input/serio/i8042-jazzio.h @@ -53,7 +53,7 @@ static inline int i8042_platform_init(void) #if 0 /* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */ if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042")) - return 1; + return -EBUSY; #endif return 0; diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index da2a198124852..ed9446f6d7e33 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -48,10 +48,10 @@ static inline void i8042_write_command(int val) #define OBP_PS2MS_NAME1 "kdmouse" #define OBP_PS2MS_NAME2 "mouse" -static int i8042_platform_init(void) +static int __init i8042_platform_init(void) { #ifndef CONFIG_PCI - return -1; + return -ENODEV; #else char prop[128]; int len; @@ -59,14 +59,14 @@ static int i8042_platform_init(void) len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); if (len < 0) { printk("i8042: Cannot get name property of root OBP node.\n"); - return -1; + return -ENODEV; } if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) { /* Hardcoded values for MrCoffee. */ i8042_kbd_irq = i8042_aux_irq = 13 | 0x20; kbd_iobase = ioremap(0x71300060, 8); if (!kbd_iobase) - return -1; + return -ENODEV; } else { struct linux_ebus *ebus; struct linux_ebus_device *edev; @@ -78,7 +78,7 @@ static int i8042_platform_init(void) goto edev_found; } } - return -1; + return -ENODEV; edev_found: for_each_edevchild(edev, child) { @@ -96,7 +96,7 @@ static int i8042_platform_init(void) i8042_aux_irq == -1) { printk("i8042: Error, 8042 device lacks both kbd and " "mouse nodes.\n"); - return -1; + return -ENODEV; } } diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 03877c84e6ff9..02bc23142ce0a 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -256,7 +256,7 @@ static void i8042_pnp_exit(void) } } -static int i8042_pnp_init(void) +static int __init i8042_pnp_init(void) { int result_kbd, result_aux; @@ -322,25 +322,29 @@ static int i8042_pnp_init(void) return 0; } +#else +static inline int i8042_pnp_init(void) { return 0; } +static inline void i8042_pnp_exit(void) { } #endif -static inline int i8042_platform_init(void) +static int __init i8042_platform_init(void) { + int retval; + /* * On ix86 platforms touching the i8042 data register region can do really * bad things. Because of this the region is always reserved on ix86 boxes. * * if (!request_region(I8042_DATA_REG, 16, "i8042")) - * return -1; + * return -EBUSY; */ i8042_kbd_irq = I8042_MAP_IRQ(1); i8042_aux_irq = I8042_MAP_IRQ(12); -#ifdef CONFIG_PNP - if (i8042_pnp_init()) - return -1; -#endif + retval = i8042_pnp_init(); + if (retval) + return retval; #if defined(__ia64__) i8042_reset = 1; @@ -354,14 +358,12 @@ static inline int i8042_platform_init(void) i8042_nomux = 1; #endif - return 0; + return retval; } static inline void i8042_platform_exit(void) { -#ifdef CONFIG_PNP i8042_pnp_exit(); -#endif } #endif /* _I8042_X86IA64IO_H */ diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index f0d9c5f9cc368..2a76d08c4d3e5 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1066,8 +1066,9 @@ static int __init i8042_init(void) init_timer(&i8042_timer); i8042_timer.function = i8042_timer_func; - if (i8042_platform_init()) - return -EBUSY; + err = i8042_platform_init(); + if (err) + return err; i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ; i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ; -- GitLab From c3d31e7f9a94800ba895a081e143e79954f6c62f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov <dtor_core@ameritech.net> Date: Sun, 4 Sep 2005 01:41:51 -0500 Subject: [PATCH 015/563] Input: i8042 - fix IRQ printing when either KBD or AUX port is absent from ACPI/PNP tables. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/serio/i8042-x86ia64io.h | 39 +++++++++++++++++---------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 02bc23142ce0a..84a73bc6afdc8 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -258,7 +258,8 @@ static void i8042_pnp_exit(void) static int __init i8042_pnp_init(void) { - int result_kbd, result_aux; + int result_kbd = 0, result_aux = 0; + char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 }; if (i8042_nopnp) { printk(KERN_INFO "i8042: PNP detection disabled\n"); @@ -267,6 +268,7 @@ static int __init i8042_pnp_init(void) if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0) i8042_pnp_kbd_registered = 1; + if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0) i8042_pnp_aux_registered = 1; @@ -280,6 +282,25 @@ static int __init i8042_pnp_init(void) #endif } + if (result_kbd > 0) + snprintf(kbd_irq_str, sizeof(kbd_irq_str), + "%d", i8042_pnp_kbd_irq); + if (result_aux > 0) + snprintf(aux_irq_str, sizeof(aux_irq_str), + "%d", i8042_pnp_aux_irq); + + printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n", + i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", + i8042_pnp_aux_name, + i8042_pnp_data_reg, i8042_pnp_command_reg, + kbd_irq_str, (result_kbd > 0 && result_aux > 0) ? "," : "", + aux_irq_str); + +#if defined(__ia64__) + if (result_aux <= 0) + i8042_noaux = 1; +#endif + if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) && i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) { printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n", @@ -295,30 +316,20 @@ static int __init i8042_pnp_init(void) } if (!i8042_pnp_kbd_irq) { - printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %#x\n", i8042_kbd_irq); + printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %d\n", i8042_kbd_irq); i8042_pnp_kbd_irq = i8042_kbd_irq; } - if (!i8042_pnp_aux_irq) { - printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq); + if (!i8042_noaux && !i8042_pnp_aux_irq) { + printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %d\n", i8042_aux_irq); i8042_pnp_aux_irq = i8042_aux_irq; } -#if defined(__ia64__) - if (result_aux <= 0) - i8042_noaux = 1; -#endif - i8042_data_reg = i8042_pnp_data_reg; i8042_command_reg = i8042_pnp_command_reg; i8042_kbd_irq = i8042_pnp_kbd_irq; i8042_aux_irq = i8042_pnp_aux_irq; - printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %d%s%d\n", - i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", i8042_pnp_aux_name, - i8042_data_reg, i8042_command_reg, i8042_kbd_irq, - (result_aux > 0) ? "," : "", i8042_aux_irq); - return 0; } -- GitLab From 945ef0d428bc33c639e49d27fb8cc765adec3fdf Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov <dtor_core@ameritech.net> Date: Sun, 4 Sep 2005 01:42:00 -0500 Subject: [PATCH 016/563] Input: i8042 - add i8042.nokbd module option to allow supressing creation of keyboard port. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- Documentation/kernel-parameters.txt | 1 + drivers/input/serio/i8042-x86ia64io.h | 4 +++- drivers/input/serio/i8042.c | 22 ++++++++++++++++++---- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 3d5cd7a09b2fc..111e98056195d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -549,6 +549,7 @@ running once the system is up. keyboard and can not control its state (Don't attempt to blink the leds) i8042.noaux [HW] Don't check for auxiliary (== mouse) port + i8042.nokbd [HW] Don't check/create keyboard port i8042.nomux [HW] Don't check presence of an active multiplexing controller i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 84a73bc6afdc8..d5ea3cf094694 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -297,6 +297,8 @@ static int __init i8042_pnp_init(void) aux_irq_str); #if defined(__ia64__) + if (result_kbd <= 0) + i8042_nokbd = 1; if (result_aux <= 0) i8042_noaux = 1; #endif @@ -315,7 +317,7 @@ static int __init i8042_pnp_init(void) i8042_pnp_command_reg = i8042_command_reg; } - if (!i8042_pnp_kbd_irq) { + if (!i8042_nokbd && !i8042_pnp_kbd_irq) { printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %d\n", i8042_kbd_irq); i8042_pnp_kbd_irq = i8042_kbd_irq; } diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 2a76d08c4d3e5..19ef35db342ee 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -27,6 +27,10 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); MODULE_LICENSE("GPL"); +static unsigned int i8042_nokbd; +module_param_named(nokbd, i8042_nokbd, bool, 0); +MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port."); + static unsigned int i8042_noaux; module_param_named(noaux, i8042_noaux, bool, 0); MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port."); @@ -1058,7 +1062,7 @@ static int __init i8042_create_mux_port(int index) static int __init i8042_init(void) { - int i; + int i, have_ports = 0; int err; dbg_init(); @@ -1100,11 +1104,20 @@ static int __init i8042_init(void) if (err) goto err_unregister_ports; } + have_ports = 1; } - err = i8042_create_kbd_port(); - if (err) - goto err_unregister_ports; + if (!i8042_nokbd) { + err = i8042_create_kbd_port(); + if (err) + goto err_unregister_ports; + have_ports = 1; + } + + if (!have_ports) { + err = -ENODEV; + goto err_unregister_device; + } mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); @@ -1114,6 +1127,7 @@ static int __init i8042_init(void) for (i = 0; i < I8042_NUM_PORTS; i++) if (i8042_ports[i].serio) serio_unregister_port(i8042_ports[i].serio); + err_unregister_device: platform_device_unregister(i8042_platform_device); err_unregister_driver: driver_unregister(&i8042_driver); -- GitLab From 7545c24c6a6ab62922266197a72119212280ea2a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov <dtor_core@ameritech.net> Date: Sun, 4 Sep 2005 01:42:10 -0500 Subject: [PATCH 017/563] Input: i8042 - add Lifebook E4010 to MUX blacklist Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index d5ea3cf094694..273bb3b08cfa2 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -137,6 +137,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), }, }, + { + .ident = "Fujitsu-Siemens Lifebook E4010", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), + }, + }, { .ident = "Toshiba P10", .matches = { -- GitLab From b8c9c642db4ab0811cc5bb0d8b90cc7819055c95 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Mon, 5 Sep 2005 00:07:37 -0500 Subject: [PATCH 018/563] Inpur: recognize and ignore Logitech vendor usages in HID These get in our way with MX mice. Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hid-input.c | 1 + drivers/usb/input/hid.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 63a4db721f7e5..3b162a19d7b52 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -296,6 +296,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel break; case HID_UP_MSVENDOR: + case HID_UP_LOGIVENDOR: goto ignore; diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index c1b6b69bc4a46..f3b85a0c200ce 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -182,6 +182,7 @@ struct hid_item { #define HID_UP_PID 0x000f0000 #define HID_UP_HPVENDOR 0xff7f0000 #define HID_UP_MSVENDOR 0xff000000 +#define HID_UP_LOGIVENDOR 0x00ff0000 #define HID_USAGE 0x0000ffff -- GitLab From 0aebfdac042b63d0f2625414062e138a4333181c Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Mon, 5 Sep 2005 00:07:59 -0500 Subject: [PATCH 019/563] Input: add HID simulation mappings Add simulation usage page mappings to hid-input.c to support a new crop of joysticks using them to designate Rudder and Throttle controls. Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hid-debug.h | 17 +++++++++++++++++ drivers/usb/input/hid-input.c | 9 +++++++++ drivers/usb/input/hid.h | 1 + 3 files changed, 27 insertions(+) diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h index 52437e5e2e780..789df807b1136 100644 --- a/drivers/usb/input/hid-debug.h +++ b/drivers/usb/input/hid-debug.h @@ -85,6 +85,23 @@ static const struct hid_usage_entry hid_usage_table[] = { {0, 0x91, "D-PadDown"}, {0, 0x92, "D-PadRight"}, {0, 0x93, "D-PadLeft"}, + { 2, 0, "Simulation" }, + {0, 0xb0, "Aileron"}, + {0, 0xb1, "AileronTrim"}, + {0, 0xb2, "Anti-Torque"}, + {0, 0xb3, "Autopilot"}, + {0, 0xb4, "Chaff"}, + {0, 0xb5, "Collective"}, + {0, 0xb6, "DiveBrake"}, + {0, 0xb7, "ElectronicCountermeasures"}, + {0, 0xb8, "Elevator"}, + {0, 0xb9, "ElevatorTrim"}, + {0, 0xba, "Rudder"}, + {0, 0xbb, "Throttle"}, + {0, 0xbc, "FlightCommunications"}, + {0, 0xbd, "FlareRelease"}, + {0, 0xbe, "LandingGear"}, + {0, 0xbf, "ToeBrake"}, { 7, 0, "Keyboard" }, { 8, 0, "LED" }, {0, 0x01, "NumLock"}, diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 3b162a19d7b52..fa4f79d88aa7d 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -131,6 +131,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel map_key(code); break; + + case HID_UP_SIMULATION: + + switch (usage->hid & 0xffff) { + case 0xba: map_abs(ABS_RUDDER); break; + case 0xbb: map_abs(ABS_THROTTLE); break; + } + break; + case HID_UP_GENDESK: if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */ diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index f3b85a0c200ce..cea5cf34b5f9b 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -173,6 +173,7 @@ struct hid_item { #define HID_UP_UNDEFINED 0x00000000 #define HID_UP_GENDESK 0x00010000 +#define HID_UP_SIMULATION 0x00020000 #define HID_UP_KEYBOARD 0x00070000 #define HID_UP_LED 0x00080000 #define HID_UP_BUTTON 0x00090000 -- GitLab From 8a409b0118c2d78f84f740f60fe03abda1fe3333 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Mon, 5 Sep 2005 00:08:08 -0500 Subject: [PATCH 020/563] Input: HID - add more consumer usages Extend mapping of the consumer usage page in hid-input.c to handle more cases appearing on new USB keyboards. Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hid-debug.h | 17 +++++++++++------ drivers/usb/input/hid-input.c | 19 ++++++++++++++++--- drivers/usb/input/hid.h | 1 + include/linux/input.h | 8 ++++++++ 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h index 789df807b1136..ceebab99eff24 100644 --- a/drivers/usb/input/hid-debug.h +++ b/drivers/usb/input/hid-debug.h @@ -109,6 +109,7 @@ static const struct hid_usage_entry hid_usage_table[] = { {0, 0x03, "ScrollLock"}, {0, 0x04, "Compose"}, {0, 0x05, "Kana"}, + {0, 0x4b, "GenericIndicator"}, { 9, 0, "Button" }, { 10, 0, "Ordinal" }, { 12, 0, "Consumer" }, @@ -591,7 +592,8 @@ static char *keys[KEY_MAX + 1] = { [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move", [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp", [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis", - [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_F13] = "F13", + [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New", + [KEY_REDO] = "Redo", [KEY_F13] = "F13", [KEY_F14] = "F14", [KEY_F15] = "F15", [KEY_F16] = "F16", [KEY_F17] = "F17", [KEY_F18] = "F18", [KEY_F19] = "F19", @@ -601,15 +603,15 @@ static char *keys[KEY_MAX + 1] = { [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3", [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend", [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play", - [KEY_FASTFORWARD] = "Fast Forward", [KEY_BASSBOOST] = "Bass Boost", + [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost", [KEY_PRINT] = "Print", [KEY_HP] = "HP", [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound", [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email", [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search", [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance", [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop", - [KEY_ALTERASE] = "Alternate Erase", [KEY_CANCEL] = "Cancel", - [KEY_BRIGHTNESSDOWN] = "Brightness down", [KEY_BRIGHTNESSUP] = "Brightness up", + [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel", + [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp", [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", [BTN_0] = "Btn0", [BTN_1] = "Btn1", [BTN_2] = "Btn2", [BTN_3] = "Btn3", @@ -639,8 +641,8 @@ static char *keys[KEY_MAX + 1] = { [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger", [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", - [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "Tool Doubletap", - [BTN_TOOL_TRIPLETAP] = "Tool Tripletap", [BTN_GEAR_DOWN] = "WheelBtn", + [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", + [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn", [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", @@ -676,6 +678,9 @@ static char *keys[KEY_MAX + 1] = { [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL", [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine", [KEY_DEL_LINE] = "DeleteLine", + [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", + [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", + [KEY_DOCUMENTS] = "Documents", }; static char *relatives[REL_MAX + 1] = { diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index fa4f79d88aa7d..b28cf8593b48a 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -78,8 +78,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel { struct input_dev *input = &hidinput->input; struct hid_device *device = hidinput->input.private; - int max, code; - unsigned long *bit; + int max = 0, code; + unsigned long *bit = NULL; field->hidinput = hidinput; @@ -248,7 +248,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x034: map_key_clear(KEY_SLEEP); break; case 0x036: map_key_clear(BTN_MISC); break; case 0x08a: map_key_clear(KEY_WWW); break; + case 0x08d: map_key_clear(KEY_PROGRAM); break; case 0x095: map_key_clear(KEY_HELP); break; + case 0x09c: map_key_clear(KEY_CHANNELUP); break; + case 0x09d: map_key_clear(KEY_CHANNELDOWN); break; case 0x0b0: map_key_clear(KEY_PLAY); break; case 0x0b1: map_key_clear(KEY_PAUSE); break; case 0x0b2: map_key_clear(KEY_RECORD); break; @@ -268,6 +271,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x18a: map_key_clear(KEY_MAIL); break; case 0x192: map_key_clear(KEY_CALC); break; case 0x194: map_key_clear(KEY_FILE); break; + case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; + case 0x201: map_key_clear(KEY_NEW); break; + case 0x207: map_key_clear(KEY_SAVE); break; + case 0x208: map_key_clear(KEY_PRINT); break; + case 0x209: map_key_clear(KEY_PROPS); break; case 0x21a: map_key_clear(KEY_UNDO); break; case 0x21b: map_key_clear(KEY_COPY); break; case 0x21c: map_key_clear(KEY_CUT); break; @@ -280,7 +288,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x227: map_key_clear(KEY_REFRESH); break; case 0x22a: map_key_clear(KEY_BOOKMARKS); break; case 0x238: map_rel(REL_HWHEEL); break; - default: goto unknown; + case 0x279: map_key_clear(KEY_REDO); break; + case 0x289: map_key_clear(KEY_REPLY); break; + case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; + case 0x28c: map_key_clear(KEY_SEND); break; + default: goto ignore; } break; @@ -306,6 +318,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_UP_MSVENDOR: case HID_UP_LOGIVENDOR: + case HID_UP_LOGIVENDOR2: goto ignore; diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index cea5cf34b5f9b..ca3e170ce0b35 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -184,6 +184,7 @@ struct hid_item { #define HID_UP_HPVENDOR 0xff7f0000 #define HID_UP_MSVENDOR 0xff000000 #define HID_UP_LOGIVENDOR 0x00ff0000 +#define HID_UP_LOGIVENDOR2 0xffbc0000 #define HID_USAGE 0x0000ffff diff --git a/include/linux/input.h b/include/linux/input.h index bdc53c6cc962a..227a497c06782 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -287,6 +287,8 @@ struct input_absinfo { #define KEY_SCROLLDOWN 178 #define KEY_KPLEFTPAREN 179 #define KEY_KPRIGHTPAREN 180 +#define KEY_NEW 181 +#define KEY_REDO 182 #define KEY_F13 183 #define KEY_F14 184 @@ -333,6 +335,12 @@ struct input_absinfo { #define KEY_KBDILLUMDOWN 229 #define KEY_KBDILLUMUP 230 +#define KEY_SEND 231 +#define KEY_REPLY 232 +#define KEY_FORWARDMAIL 233 +#define KEY_SAVE 234 +#define KEY_DOCUMENTS 235 + #define KEY_UNKNOWN 240 #define BTN_MISC 0x100 -- GitLab From 903b126bffb77dc313b7c2971880df408bf41a9e Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Mon, 5 Sep 2005 00:11:41 -0500 Subject: [PATCH 021/563] Input: atkbd - handle keyboards generating scancode 0x7f Extend bat_xl handling to do err_xl handling, so that keyboards using 0x7f scancode for regular keys can work. Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/keyboard/atkbd.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 4d4985b59abf1..1ad8c2ee7dbf3 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -208,6 +208,7 @@ struct atkbd { unsigned char resend; unsigned char release; unsigned char bat_xl; + unsigned char err_xl; unsigned int last; unsigned long time; }; @@ -296,15 +297,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, if (atkbd->emul || !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 || code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA || - code == ATKBD_RET_ERR || + (code == ATKBD_RET_ERR && !atkbd->err_xl) || (code == ATKBD_RET_BAT && !atkbd->bat_xl))) { atkbd->release = code >> 7; code &= 0x7f; } - if (!atkbd->emul && - (code & 0x7f) == (ATKBD_RET_BAT & 0x7f)) + if (!atkbd->emul) { + if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f)) atkbd->bat_xl = !atkbd->release; + if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f)) + atkbd->err_xl = !atkbd->release; + } } switch (code) { -- GitLab From bf0964dcda97e42964d312d0ff73a832171e080a Mon Sep 17 00:00:00 2001 From: Michael Haboustak <mike-@cinci.rr.com> Date: Mon, 5 Sep 2005 00:12:01 -0500 Subject: [PATCH 022/563] Input: HID - handle multi-transascion reports Fixes handling of multi-transaction reports for HID devices. New function hid_size_buffers() that calculates the longest report for each endpoint and stores the result in the hid_device object. These lengths are used to allocate buffers that are large enough to store any report on the endpoint. For compatibility, the minimum size for an endpoint buffer set to HID_BUFFER_SIZE rather than the known optimal case (the longest report length). It fixes bug #3063 in bugzilla. Signed-off-by: Michael Haboustak <mike-@cinci.rr.com> I simplified the patch a bit to use just a single buffer size. Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hid-core.c | 62 +++++++++++++++++++++++++----------- drivers/usb/input/hid.h | 5 ++- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index b2cb2b35892e5..376b6043bbff6 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -2,7 +2,8 @@ * USB HID support for Linux * * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz> + * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> + * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc */ /* @@ -38,7 +39,7 @@ * Version Information */ -#define DRIVER_VERSION "v2.01" +#define DRIVER_VERSION "v2.6" #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik" #define DRIVER_DESC "USB HID core driver" #define DRIVER_LICENSE "GPL" @@ -1058,8 +1059,8 @@ static int hid_submit_ctrl(struct hid_device *hid) if (maxpacket > 0) { padlen = (len + maxpacket - 1) / maxpacket; padlen *= maxpacket; - if (padlen > HID_BUFFER_SIZE) - padlen = HID_BUFFER_SIZE; + if (padlen > hid->bufsize) + padlen = hid->bufsize; } else padlen = 0; hid->urbctrl->transfer_buffer_length = padlen; @@ -1284,13 +1285,8 @@ void hid_init_reports(struct hid_device *hid) struct hid_report *report; int err, ret; - list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) { - int size = ((report->size - 1) >> 3) + 1 + hid->report_enum[HID_INPUT_REPORT].numbered; - if (size > HID_BUFFER_SIZE) size = HID_BUFFER_SIZE; - if (size > hid->urbin->transfer_buffer_length) - hid->urbin->transfer_buffer_length = size; + list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) hid_submit_report(hid, report, USB_DIR_IN); - } list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) hid_submit_report(hid, report, USB_DIR_IN); @@ -1564,15 +1560,32 @@ static struct hid_blacklist { { 0, 0 } }; +/* + * Traverse the supplied list of reports and find the longest + */ +static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max) +{ + struct hid_report *report; + int size; + + list_for_each_entry(report, &hid->report_enum[type].report_list, list) { + size = ((report->size - 1) >> 3) + 1; + if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered) + size++; + if (*max < size) + *max = size; + } +} + static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) { - if (!(hid->inbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->inbuf_dma))) + if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->inbuf_dma))) return -1; - if (!(hid->outbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->outbuf_dma))) + if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->outbuf_dma))) return -1; if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), SLAB_ATOMIC, &hid->cr_dma))) return -1; - if (!(hid->ctrlbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->ctrlbuf_dma))) + if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->ctrlbuf_dma))) return -1; return 0; @@ -1581,13 +1594,13 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) { if (hid->inbuf) - usb_buffer_free(dev, HID_BUFFER_SIZE, hid->inbuf, hid->inbuf_dma); + usb_buffer_free(dev, hid->bufsize, hid->inbuf, hid->inbuf_dma); if (hid->outbuf) - usb_buffer_free(dev, HID_BUFFER_SIZE, hid->outbuf, hid->outbuf_dma); + usb_buffer_free(dev, hid->bufsize, hid->outbuf, hid->outbuf_dma); if (hid->cr) usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma); if (hid->ctrlbuf) - usb_buffer_free(dev, HID_BUFFER_SIZE, hid->ctrlbuf, hid->ctrlbuf_dma); + usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma); } static struct hid_device *usb_hid_configure(struct usb_interface *intf) @@ -1598,7 +1611,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) struct hid_device *hid; unsigned quirks = 0, rsize = 0; char *buf, *rdesc; - int n; + int n, insize = 0; for (n = 0; hid_blacklist[n].idVendor; n++) if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) && @@ -1652,6 +1665,19 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) kfree(rdesc); hid->quirks = quirks; + hid->bufsize = HID_MIN_BUFFER_SIZE; + hid_find_max_report(hid, HID_INPUT_REPORT, &hid->bufsize); + hid_find_max_report(hid, HID_OUTPUT_REPORT, &hid->bufsize); + hid_find_max_report(hid, HID_FEATURE_REPORT, &hid->bufsize); + + if (hid->bufsize > HID_MAX_BUFFER_SIZE) + hid->bufsize = HID_MAX_BUFFER_SIZE; + + hid_find_max_report(hid, HID_INPUT_REPORT, &insize); + + if (insize > HID_MAX_BUFFER_SIZE) + insize = HID_MAX_BUFFER_SIZE; + if (hid_alloc_buffers(dev, hid)) { hid_free_buffers(dev, hid); goto fail; @@ -1682,7 +1708,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0, + usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, insize, hid_irq_in, hid, interval); hid->urbin->transfer_dma = hid->inbuf_dma; hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index ca3e170ce0b35..d76bbc81f6a8d 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -351,7 +351,8 @@ struct hid_report_enum { #define HID_REPORT_TYPES 3 -#define HID_BUFFER_SIZE 64 /* use 64 for compatibility with all possible packetlen */ +#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ +#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */ #define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ #define HID_OUTPUT_FIFO_SIZE 64 @@ -389,6 +390,8 @@ struct hid_device { /* device report descriptor */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ + unsigned int bufsize; /* URB buffer size */ + struct urb *urbin; /* Input URB */ char *inbuf; /* Input buffer */ dma_addr_t inbuf_dma; /* Input buffer dma */ -- GitLab From 39fd748f56012fdde4cf862f127ce4cdec50d661 Mon Sep 17 00:00:00 2001 From: "Micah F. Galizia" <mfgalizi@uwo.ca> Date: Mon, 5 Sep 2005 00:12:15 -0500 Subject: [PATCH 023/563] Input: HID - add support for Logitech UltraX Media Remote control The hid now supports the Logitech UltraX Media Remote control. For now, ID 45 on the consumer usage page has been incorrectly mapped to KEY_RADIO since no other devices uses it. Signed-off-by: Micah F. Galizia <mfgalizi@csd.uwo.ca> Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hid-input.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index b28cf8593b48a..22f9d919a3f2c 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -247,6 +247,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x000: goto ignore; case 0x034: map_key_clear(KEY_SLEEP); break; case 0x036: map_key_clear(BTN_MISC); break; + case 0x045: map_key_clear(KEY_RADIO); break; case 0x08a: map_key_clear(KEY_WWW); break; case 0x08d: map_key_clear(KEY_PROGRAM); break; case 0x095: map_key_clear(KEY_HELP); break; @@ -318,10 +319,33 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_UP_MSVENDOR: case HID_UP_LOGIVENDOR: - case HID_UP_LOGIVENDOR2: - goto ignore; + case HID_UP_LOGIVENDOR2: /* Reported on Logitech Ultra X Media Remote */ + + set_bit(EV_REP, input->evbit); + switch(usage->hid & HID_USAGE) { + case 0x004: map_key_clear(KEY_AGAIN); break; + case 0x00d: map_key_clear(KEY_HOME); break; + case 0x024: map_key_clear(KEY_SHUFFLE); break; + case 0x025: map_key_clear(KEY_TV); break; + case 0x026: map_key_clear(KEY_MENU); break; + case 0x031: map_key_clear(KEY_AUDIO); break; + case 0x032: map_key_clear(KEY_SUBTITLE); break; + case 0x033: map_key_clear(KEY_LAST); break; + case 0x047: map_key_clear(KEY_MP3); break; + case 0x048: map_key_clear(KEY_DVD); break; + case 0x049: map_key_clear(KEY_MEDIA); break; + case 0x04a: map_key_clear(KEY_VIDEO); break; + case 0x04b: map_key_clear(KEY_ANGLE); break; + case 0x04c: map_key_clear(KEY_LANGUAGE); break; + case 0x04d: map_key_clear(KEY_SUBTITLE); break; + case 0x051: map_key_clear(KEY_RED); break; + case 0x052: map_key_clear(KEY_CLOSE); break; + default: goto ignore; + } + break; + case HID_UP_PID: set_bit(EV_FF, input->evbit); -- GitLab From fb76b099f86624d3c629cfab071aa2296f65b7bb Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Mon, 5 Sep 2005 00:12:39 -0500 Subject: [PATCH 024/563] Input: iforce - use wait_event_interruptible_timeout The timeout while() loops in iforce-packets.c lack a set_current_state(TASK_INTERRUPTIBLE); call. The right solution is to replace them with wait_event_interruptible_timeout(). Reported-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- .../input/joystick/iforce/iforce-packets.c | 32 ++++--------------- drivers/input/joystick/iforce/iforce-usb.c | 1 + 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 58728ebaaf80c..e5a31e55d3e24 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -249,9 +249,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, int iforce_get_id_packet(struct iforce *iforce, char *packet) { - DECLARE_WAITQUEUE(wait, current); - int timeout = HZ; /* 1 second */ - switch (iforce->bus) { case IFORCE_USB: @@ -260,22 +257,13 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet) iforce->cr.bRequest = packet[0]; iforce->ctrl->dev = iforce->usbdev; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&iforce->wait, &wait); - - if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); + if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) return -1; - } - while (timeout && iforce->ctrl->status == -EINPROGRESS) - timeout = schedule_timeout(timeout); + wait_event_interruptible_timeout(iforce->wait, + iforce->ctrl->status != -EINPROGRESS, HZ); - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); - - if (!timeout) { + if (iforce->ctrl->status != -EINPROGRESS) { usb_unlink_urb(iforce->ctrl); return -1; } @@ -290,16 +278,10 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet) iforce->expect_packet = FF_CMD_QUERY; iforce_send_packet(iforce, FF_CMD_QUERY, packet); - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&iforce->wait, &wait); - - while (timeout && iforce->expect_packet) - timeout = schedule_timeout(timeout); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&iforce->wait, &wait); + wait_event_interruptible_timeout(iforce->wait, + !iforce->expect_packet, HZ); - if (!timeout) { + if (iforce->expect_packet) { iforce->expect_packet = 0; return -1; } diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 6369a24684fe3..58600f91eff52 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -95,6 +95,7 @@ static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs) goto exit; } + wake_up(&iforce->wait); iforce_process_packet(iforce, (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1, regs); -- GitLab From 8d9a9ae3b2941d94bb0023a3aca2ec2bfa83d0c2 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Mon, 5 Sep 2005 00:12:47 -0500 Subject: [PATCH 025/563] Input: sunkbd - extend mapping to handle Type-6 Sun keyboards Map an unmarked key at 'Esc' position to KEY_MACRO Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/keyboard/sunkbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 596964ceb96dc..4bae5d89348d7 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -44,7 +44,7 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static unsigned char sunkbd_keycode[128] = { - 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64, 0, + 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,112, 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55, 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -- GitLab From c4786ca8a4274a0bbffe217917972943348bed64 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Mon, 5 Sep 2005 00:13:03 -0500 Subject: [PATCH 026/563] Input: HID - fix URB success status handling Add a missing break; statement to the URB status handling in hid-core.c, avoiding flushing the request queue on success. Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hid-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 376b6043bbff6..7d5eb4deb1ef1 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1097,6 +1097,7 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs) switch (urb->status) { case 0: /* success */ + break; case -ESHUTDOWN: /* unplug */ case -EILSEQ: /* unplug timeout on uhci */ unplug = 1; @@ -1144,6 +1145,7 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs) case 0: /* success */ if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs); + break; case -ESHUTDOWN: /* unplug */ case -EILSEQ: /* unplug timectrl on uhci */ unplug = 1; -- GitLab From c58de6d949a9d2c386c4d814013b6c967c14ea5a Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Mon, 5 Sep 2005 00:13:15 -0500 Subject: [PATCH 027/563] Input: HID - add a quirk for the Apple Powermouse Add a quirk for the Apple Powermouse, remapping GenericDesktop.Z to Rel.HWheel, to allow horizontal scrolling in Linux. Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hid-core.c | 3 +++ drivers/usb/input/hid-input.c | 3 +++ drivers/usb/input/hid.h | 1 + 3 files changed, 7 insertions(+) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 7d5eb4deb1ef1..661709a35b0eb 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1442,6 +1442,8 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_NETWORKANALYSER 0x2020 #define USB_DEVICE_ID_POWERCONTROL 0x2030 +#define USB_VENDOR_ID_APPLE 0x05ac +#define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304 /* * Alphabetically sorted blacklist by quirk type. @@ -1546,6 +1548,7 @@ static struct hid_blacklist { { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET}, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_POWERMOUSE, HID_QUIRK_2WHEEL_POWERMOUSE }, { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 22f9d919a3f2c..14acfc579f862 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -396,6 +396,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel if (usage->code > max) goto ignore; + if (((device->quirks & (HID_QUIRK_2WHEEL_POWERMOUSE)) && (usage->hid == 0x00010032))) + map_rel(REL_HWHEEL); + if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && (usage->type == EV_REL) && (usage->code == REL_WHEEL)) set_bit(REL_HWHEEL, bit); diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index d76bbc81f6a8d..47f75a43a4685 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -245,6 +245,7 @@ struct hid_item { #define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x080 #define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x100 #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x200 +#define HID_QUIRK_2WHEEL_POWERMOUSE 0x400 /* * This is the global environment of the parser. This information is -- GitLab From 61cdecd9f5f602775af1e89c200179d093a94ae2 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik <vojtech@suse.cz> Date: Mon, 5 Sep 2005 00:13:32 -0500 Subject: [PATCH 028/563] Input: HID - add the Trust Predator TH 400 gamepad to the badpad list Reported-by: Karl Relton <karllinuxtest.relton@ntlworld.com> Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hid-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 661709a35b0eb..485575a70be57 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1370,8 +1370,9 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_A4TECH 0x09da #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 -#define USB_VENDOR_ID_AASHIMA 0x06D6 +#define USB_VENDOR_ID_AASHIMA 0x06d6 #define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 +#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026 #define USB_VENDOR_ID_CYPRESS 0x04b4 #define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 @@ -1553,6 +1554,7 @@ static struct hid_blacklist { { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, -- GitLab From e875ce374759087771313c9e76b672b86ac20950 Mon Sep 17 00:00:00 2001 From: Stelian Pop <stelian@popies.net> Date: Mon, 5 Sep 2005 01:57:33 -0500 Subject: [PATCH 029/563] Input: HID - add mapping for Powerbook USB keyboard Map custom HID events (such as the ones generated by some Logitech and Apple Powerbooks USB keyboards) to the FN keycode. Signed-off-by: Stelian Pop <stelian@popies.net> Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hid-input.c | 12 ++++++++++-- drivers/usb/input/hid.h | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 14acfc579f862..0b6452248a398 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -318,10 +318,18 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel break; case HID_UP_MSVENDOR: - case HID_UP_LOGIVENDOR: goto ignore; - case HID_UP_LOGIVENDOR2: /* Reported on Logitech Ultra X Media Remote */ + case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */ + + set_bit(EV_REP, input->evbit); + switch(usage->hid & HID_USAGE) { + case 0x003: map_key_clear(KEY_FN); break; + default: goto ignore; + } + break; + + case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */ set_bit(EV_REP, input->evbit); switch(usage->hid & HID_USAGE) { diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 47f75a43a4685..ec2412c42f1ea 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -183,8 +183,8 @@ struct hid_item { #define HID_UP_PID 0x000f0000 #define HID_UP_HPVENDOR 0xff7f0000 #define HID_UP_MSVENDOR 0xff000000 -#define HID_UP_LOGIVENDOR 0x00ff0000 -#define HID_UP_LOGIVENDOR2 0xffbc0000 +#define HID_UP_CUSTOM 0x00ff0000 +#define HID_UP_LOGIVENDOR 0xffbc0000 #define HID_USAGE 0x0000ffff -- GitLab From 7d25258f69cedc2f2e55eb25ba2e2078060b44f4 Mon Sep 17 00:00:00 2001 From: Brian Schau <brian@schau.com> Date: Mon, 5 Sep 2005 01:57:41 -0500 Subject: [PATCH 030/563] Input: HID - add Wireless Security Lock to HID blacklist The device is a Wireless Security Lock (WSL). The device identifies itself as a Cypress Ultra Mouse. It is, however, not a mouse at all and as such, shouldn't be handled as one. Signed-off-by: Brian Schau <brian@schau.com> Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hid-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 485575a70be57..a721299004576 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1377,6 +1377,7 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_CYPRESS 0x04b4 #define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 #define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 +#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417 #define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 @@ -1469,6 +1470,7 @@ static struct hid_blacklist { { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, -- GitLab From 010988e888a0abbe7118635c1b33d049caae6b29 Mon Sep 17 00:00:00 2001 From: Stefan Nickl <Stefan.Nickl@kontron.com> Date: Mon, 5 Sep 2005 01:57:46 -0500 Subject: [PATCH 031/563] Input: HIDDEV - make HIDIOCSREPORT wait IO completion When trying to make the hiddev driver issue several Set_Report control transfers to a custom device with 2.6.13-rc6, only the first transfer in a row is carried out, while others immediately following it are silently dropped. This happens where hid_submit_report() (in hid-core.c) tests for HID_CTRL_RUNNING, which seems to be still set because the first transfer is not finished yet. As a workaround, inserting a delay between the two calls to ioctl(HIDIOCSREPORT) in userspace "solves" the problem. The straightforward fix is to add a call to hid_wait_io() to the implementation of HIDIOCSREPORT (in hiddev.c), just like for HIDIOCGREPORT. Works fine for me. Apparently, this issue has some history: http://marc.theaimsgroup.com/?l=linux-usb-users&m=111100670105558&w=2 Signed-off-by: Stefan Nickl <Stefan.Nickl@kontron.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Vojtech Pavlik <vojtech@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/usb/input/hiddev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 4c13331b5f41d..d32427818af78 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -507,6 +507,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd return -EINVAL; hid_submit_report(hid, report, USB_DIR_OUT); + hid_wait_io(hid); return 0; -- GitLab From 06c56e44f3e32a859420ecac97996cc6f12827bb Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" <mst@mellanox.co.il> Date: Thu, 1 Sep 2005 09:19:02 -0700 Subject: [PATCH 032/563] [PATCH] IPoIB: fix memory leak Fix IPoIB memory leak on device removal. Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 0e8ac138e355b..49d120d2b92c5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1062,6 +1062,8 @@ static void ipoib_remove_one(struct ib_device *device) ipoib_dev_cleanup(priv->dev); free_netdev(priv->dev); } + + kfree(dev_list); } static int __init ipoib_init_module(void) -- GitLab From 1d6801f9dd3ebb054ae685153a01b1a4ec817f46 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" <mst@mellanox.co.il> Date: Thu, 1 Sep 2005 09:19:44 -0700 Subject: [PATCH 033/563] [PATCH] IB/sa_query: avoid unnecessary list scan Using ib_get_client_data in SA event handler performs a list scan. It's better to use container_of to get the sa device directly. Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/core/sa_query.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 126ac80db7b84..9191793c9007a 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -431,8 +431,8 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event event->event == IB_EVENT_LID_CHANGE || event->event == IB_EVENT_PKEY_CHANGE || event->event == IB_EVENT_SM_CHANGE) { - struct ib_sa_device *sa_dev = - ib_get_client_data(event->device, &sa_client); + struct ib_sa_device *sa_dev; + sa_dev = container_of(handler, typeof(*sa_dev), event_handler); schedule_work(&sa_dev->port[event->element.port_num - sa_dev->start_port].update_task); -- GitLab From 0b2b35f68140ceeb1b78ef85680198e63ebc8649 Mon Sep 17 00:00:00 2001 From: Sean Hefty <sean.hefty@intel.com> Date: Thu, 1 Sep 2005 09:28:03 -0700 Subject: [PATCH 034/563] [PATCH] IB: Add user-supplied context to userspace CM ABI - Add user specified context to all uCM events. Users will not retrieve any events associated with the context after destroying the corresponding cm_id. - Provide the ib_cm_init_qp_attr() call to userspace clients of the CM. This call may be used to set QP attributes properly before modifying the QP. - Fixes some error handling synchonization and cleanup issues. - Performs some minor code cleanup. Signed-off-by: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/core/ucm.c | 287 ++++++++++++++++++++++------------ drivers/infiniband/core/ucm.h | 11 +- include/rdma/ib_user_cm.h | 72 ++++++++- 3 files changed, 261 insertions(+), 109 deletions(-) diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 79595826ccc73..d0f0b0a2edd33 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -72,7 +72,6 @@ enum { static struct semaphore ctx_id_mutex; static struct idr ctx_id_table; -static int ctx_id_rover = 0; static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) { @@ -97,33 +96,16 @@ static void ib_ucm_ctx_put(struct ib_ucm_context *ctx) wake_up(&ctx->wait); } -static ssize_t ib_ucm_destroy_ctx(struct ib_ucm_file *file, int id) +static inline int ib_ucm_new_cm_id(int event) { - struct ib_ucm_context *ctx; - struct ib_ucm_event *uevent; - - down(&ctx_id_mutex); - ctx = idr_find(&ctx_id_table, id); - if (!ctx) - ctx = ERR_PTR(-ENOENT); - else if (ctx->file != file) - ctx = ERR_PTR(-EINVAL); - else - idr_remove(&ctx_id_table, ctx->id); - up(&ctx_id_mutex); - - if (IS_ERR(ctx)) - return PTR_ERR(ctx); - - atomic_dec(&ctx->ref); - wait_event(ctx->wait, !atomic_read(&ctx->ref)); + return event == IB_CM_REQ_RECEIVED || event == IB_CM_SIDR_REQ_RECEIVED; +} - /* No new events will be generated after destroying the cm_id. */ - if (!IS_ERR(ctx->cm_id)) - ib_destroy_cm_id(ctx->cm_id); +static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx) +{ + struct ib_ucm_event *uevent; - /* Cleanup events not yet reported to the user. */ - down(&file->mutex); + down(&ctx->file->mutex); list_del(&ctx->file_list); while (!list_empty(&ctx->events)) { @@ -133,15 +115,12 @@ static ssize_t ib_ucm_destroy_ctx(struct ib_ucm_file *file, int id) list_del(&uevent->ctx_list); /* clear incoming connections. */ - if (uevent->cm_id) + if (ib_ucm_new_cm_id(uevent->resp.event)) ib_destroy_cm_id(uevent->cm_id); kfree(uevent); } - up(&file->mutex); - - kfree(ctx); - return 0; + up(&ctx->file->mutex); } static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) @@ -153,36 +132,31 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) if (!ctx) return NULL; + memset(ctx, 0, sizeof *ctx); atomic_set(&ctx->ref, 1); init_waitqueue_head(&ctx->wait); ctx->file = file; - INIT_LIST_HEAD(&ctx->events); - list_add_tail(&ctx->file_list, &file->ctxs); - - ctx_id_rover = (ctx_id_rover + 1) & INT_MAX; -retry: - result = idr_pre_get(&ctx_id_table, GFP_KERNEL); - if (!result) - goto error; + do { + result = idr_pre_get(&ctx_id_table, GFP_KERNEL); + if (!result) + goto error; - down(&ctx_id_mutex); - result = idr_get_new_above(&ctx_id_table, ctx, ctx_id_rover, &ctx->id); - up(&ctx_id_mutex); + down(&ctx_id_mutex); + result = idr_get_new(&ctx_id_table, ctx, &ctx->id); + up(&ctx_id_mutex); + } while (result == -EAGAIN); - if (result == -EAGAIN) - goto retry; if (result) goto error; + list_add_tail(&ctx->file_list, &file->ctxs); ucm_dbg("Allocated CM ID <%d>\n", ctx->id); - return ctx; + error: - list_del(&ctx->file_list); kfree(ctx); - return NULL; } /* @@ -219,12 +193,9 @@ static void ib_ucm_event_path_get(struct ib_ucm_path_rec *upath, kpath->packet_life_time_selector; } -static void ib_ucm_event_req_get(struct ib_ucm_context *ctx, - struct ib_ucm_req_event_resp *ureq, +static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq, struct ib_cm_req_event_param *kreq) { - ureq->listen_id = ctx->id; - ureq->remote_ca_guid = kreq->remote_ca_guid; ureq->remote_qkey = kreq->remote_qkey; ureq->remote_qpn = kreq->remote_qpn; @@ -259,14 +230,6 @@ static void ib_ucm_event_rep_get(struct ib_ucm_rep_event_resp *urep, urep->srq = krep->srq; } -static void ib_ucm_event_sidr_req_get(struct ib_ucm_context *ctx, - struct ib_ucm_sidr_req_event_resp *ureq, - struct ib_cm_sidr_req_event_param *kreq) -{ - ureq->listen_id = ctx->id; - ureq->pkey = kreq->pkey; -} - static void ib_ucm_event_sidr_rep_get(struct ib_ucm_sidr_rep_event_resp *urep, struct ib_cm_sidr_rep_event_param *krep) { @@ -275,15 +238,14 @@ static void ib_ucm_event_sidr_rep_get(struct ib_ucm_sidr_rep_event_resp *urep, urep->qpn = krep->qpn; }; -static int ib_ucm_event_process(struct ib_ucm_context *ctx, - struct ib_cm_event *evt, +static int ib_ucm_event_process(struct ib_cm_event *evt, struct ib_ucm_event *uvt) { void *info = NULL; switch (evt->event) { case IB_CM_REQ_RECEIVED: - ib_ucm_event_req_get(ctx, &uvt->resp.u.req_resp, + ib_ucm_event_req_get(&uvt->resp.u.req_resp, &evt->param.req_rcvd); uvt->data_len = IB_CM_REQ_PRIVATE_DATA_SIZE; uvt->resp.present = IB_UCM_PRES_PRIMARY; @@ -331,8 +293,8 @@ static int ib_ucm_event_process(struct ib_ucm_context *ctx, info = evt->param.apr_rcvd.apr_info; break; case IB_CM_SIDR_REQ_RECEIVED: - ib_ucm_event_sidr_req_get(ctx, &uvt->resp.u.sidr_req_resp, - &evt->param.sidr_req_rcvd); + uvt->resp.u.sidr_req_resp.pkey = + evt->param.sidr_req_rcvd.pkey; uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE; break; case IB_CM_SIDR_REP_RECEIVED: @@ -378,31 +340,24 @@ static int ib_ucm_event_handler(struct ib_cm_id *cm_id, struct ib_ucm_event *uevent; struct ib_ucm_context *ctx; int result = 0; - int id; ctx = cm_id->context; - if (event->event == IB_CM_REQ_RECEIVED || - event->event == IB_CM_SIDR_REQ_RECEIVED) - id = IB_UCM_CM_ID_INVALID; - else - id = ctx->id; - uevent = kmalloc(sizeof(*uevent), GFP_KERNEL); if (!uevent) goto err1; memset(uevent, 0, sizeof(*uevent)); - uevent->resp.id = id; + uevent->ctx = ctx; + uevent->cm_id = cm_id; + uevent->resp.uid = ctx->uid; + uevent->resp.id = ctx->id; uevent->resp.event = event->event; - result = ib_ucm_event_process(ctx, event, uevent); + result = ib_ucm_event_process(event, uevent); if (result) goto err2; - uevent->ctx = ctx; - uevent->cm_id = (id == IB_UCM_CM_ID_INVALID) ? cm_id : NULL; - down(&ctx->file->mutex); list_add_tail(&uevent->file_list, &ctx->file->events); list_add_tail(&uevent->ctx_list, &ctx->events); @@ -414,7 +369,7 @@ static int ib_ucm_event_handler(struct ib_cm_id *cm_id, kfree(uevent); err1: /* Destroy new cm_id's */ - return (id == IB_UCM_CM_ID_INVALID); + return ib_ucm_new_cm_id(event->event); } static ssize_t ib_ucm_event(struct ib_ucm_file *file, @@ -423,7 +378,7 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, { struct ib_ucm_context *ctx; struct ib_ucm_event_get cmd; - struct ib_ucm_event *uevent = NULL; + struct ib_ucm_event *uevent; int result = 0; DEFINE_WAIT(wait); @@ -436,7 +391,6 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, * wait */ down(&file->mutex); - while (list_empty(&file->events)) { if (file->filp->f_flags & O_NONBLOCK) { @@ -463,21 +417,18 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, uevent = list_entry(file->events.next, struct ib_ucm_event, file_list); - if (!uevent->cm_id) - goto user; + if (ib_ucm_new_cm_id(uevent->resp.event)) { + ctx = ib_ucm_ctx_alloc(file); + if (!ctx) { + result = -ENOMEM; + goto done; + } - ctx = ib_ucm_ctx_alloc(file); - if (!ctx) { - result = -ENOMEM; - goto done; + ctx->cm_id = uevent->cm_id; + ctx->cm_id->context = ctx; + uevent->resp.id = ctx->id; } - ctx->cm_id = uevent->cm_id; - ctx->cm_id->context = ctx; - - uevent->resp.id = ctx->id; - -user: if (copy_to_user((void __user *)(unsigned long)cmd.response, &uevent->resp, sizeof(uevent->resp))) { result = -EFAULT; @@ -485,12 +436,10 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, } if (uevent->data) { - if (cmd.data_len < uevent->data_len) { result = -ENOMEM; goto done; } - if (copy_to_user((void __user *)(unsigned long)cmd.data, uevent->data, uevent->data_len)) { result = -EFAULT; @@ -499,12 +448,10 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, } if (uevent->info) { - if (cmd.info_len < uevent->info_len) { result = -ENOMEM; goto done; } - if (copy_to_user((void __user *)(unsigned long)cmd.info, uevent->info, uevent->info_len)) { result = -EFAULT; @@ -514,6 +461,7 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, list_del(&uevent->file_list); list_del(&uevent->ctx_list); + uevent->ctx->events_reported++; kfree(uevent->data); kfree(uevent->info); @@ -545,6 +493,7 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file, if (!ctx) return -ENOMEM; + ctx->uid = cmd.uid; ctx->cm_id = ib_create_cm_id(ib_ucm_event_handler, ctx); if (IS_ERR(ctx->cm_id)) { result = PTR_ERR(ctx->cm_id); @@ -561,7 +510,14 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file, return 0; err: - ib_ucm_destroy_ctx(file, ctx->id); + down(&ctx_id_mutex); + idr_remove(&ctx_id_table, ctx->id); + up(&ctx_id_mutex); + + if (!IS_ERR(ctx->cm_id)) + ib_destroy_cm_id(ctx->cm_id); + + kfree(ctx); return result; } @@ -570,11 +526,44 @@ static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file, int in_len, int out_len) { struct ib_ucm_destroy_id cmd; + struct ib_ucm_destroy_id_resp resp; + struct ib_ucm_context *ctx; + int result = 0; + + if (out_len < sizeof(resp)) + return -ENOSPC; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - return ib_ucm_destroy_ctx(file, cmd.id); + down(&ctx_id_mutex); + ctx = idr_find(&ctx_id_table, cmd.id); + if (!ctx) + ctx = ERR_PTR(-ENOENT); + else if (ctx->file != file) + ctx = ERR_PTR(-EINVAL); + else + idr_remove(&ctx_id_table, ctx->id); + up(&ctx_id_mutex); + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + atomic_dec(&ctx->ref); + wait_event(ctx->wait, !atomic_read(&ctx->ref)); + + /* No new events will be generated after destroying the cm_id. */ + ib_destroy_cm_id(ctx->cm_id); + /* Cleanup events not yet reported to the user. */ + ib_ucm_cleanup_events(ctx); + + resp.events_reported = ctx->events_reported; + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + result = -EFAULT; + + kfree(ctx); + return result; } static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file, @@ -609,6 +598,98 @@ static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file, return result; } +static void ib_ucm_copy_ah_attr(struct ib_ucm_ah_attr *dest_attr, + struct ib_ah_attr *src_attr) +{ + memcpy(dest_attr->grh_dgid, src_attr->grh.dgid.raw, + sizeof src_attr->grh.dgid); + dest_attr->grh_flow_label = src_attr->grh.flow_label; + dest_attr->grh_sgid_index = src_attr->grh.sgid_index; + dest_attr->grh_hop_limit = src_attr->grh.hop_limit; + dest_attr->grh_traffic_class = src_attr->grh.traffic_class; + + dest_attr->dlid = src_attr->dlid; + dest_attr->sl = src_attr->sl; + dest_attr->src_path_bits = src_attr->src_path_bits; + dest_attr->static_rate = src_attr->static_rate; + dest_attr->is_global = (src_attr->ah_flags & IB_AH_GRH); + dest_attr->port_num = src_attr->port_num; +} + +static void ib_ucm_copy_qp_attr(struct ib_ucm_init_qp_attr_resp *dest_attr, + struct ib_qp_attr *src_attr) +{ + dest_attr->cur_qp_state = src_attr->cur_qp_state; + dest_attr->path_mtu = src_attr->path_mtu; + dest_attr->path_mig_state = src_attr->path_mig_state; + dest_attr->qkey = src_attr->qkey; + dest_attr->rq_psn = src_attr->rq_psn; + dest_attr->sq_psn = src_attr->sq_psn; + dest_attr->dest_qp_num = src_attr->dest_qp_num; + dest_attr->qp_access_flags = src_attr->qp_access_flags; + + dest_attr->max_send_wr = src_attr->cap.max_send_wr; + dest_attr->max_recv_wr = src_attr->cap.max_recv_wr; + dest_attr->max_send_sge = src_attr->cap.max_send_sge; + dest_attr->max_recv_sge = src_attr->cap.max_recv_sge; + dest_attr->max_inline_data = src_attr->cap.max_inline_data; + + ib_ucm_copy_ah_attr(&dest_attr->ah_attr, &src_attr->ah_attr); + ib_ucm_copy_ah_attr(&dest_attr->alt_ah_attr, &src_attr->alt_ah_attr); + + dest_attr->pkey_index = src_attr->pkey_index; + dest_attr->alt_pkey_index = src_attr->alt_pkey_index; + dest_attr->en_sqd_async_notify = src_attr->en_sqd_async_notify; + dest_attr->sq_draining = src_attr->sq_draining; + dest_attr->max_rd_atomic = src_attr->max_rd_atomic; + dest_attr->max_dest_rd_atomic = src_attr->max_dest_rd_atomic; + dest_attr->min_rnr_timer = src_attr->min_rnr_timer; + dest_attr->port_num = src_attr->port_num; + dest_attr->timeout = src_attr->timeout; + dest_attr->retry_cnt = src_attr->retry_cnt; + dest_attr->rnr_retry = src_attr->rnr_retry; + dest_attr->alt_port_num = src_attr->alt_port_num; + dest_attr->alt_timeout = src_attr->alt_timeout; +} + +static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_ucm_init_qp_attr_resp resp; + struct ib_ucm_init_qp_attr cmd; + struct ib_ucm_context *ctx; + struct ib_qp_attr qp_attr; + int result = 0; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + resp.qp_attr_mask = 0; + memset(&qp_attr, 0, sizeof qp_attr); + qp_attr.qp_state = cmd.qp_state; + result = ib_cm_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask); + if (result) + goto out; + + ib_ucm_copy_qp_attr(&resp, &qp_attr); + + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + result = -EFAULT; + +out: + ib_ucm_ctx_put(ctx); + return result; +} + static ssize_t ib_ucm_listen(struct ib_ucm_file *file, const char __user *inbuf, int in_len, int out_len) @@ -808,6 +889,7 @@ static ssize_t ib_ucm_send_rep(struct ib_ucm_file *file, ctx = ib_ucm_ctx_get(file, cmd.id); if (!IS_ERR(ctx)) { + ctx->uid = cmd.uid; result = ib_send_cm_rep(ctx->cm_id, ¶m); ib_ucm_ctx_put(ctx); } else @@ -1086,6 +1168,7 @@ static ssize_t (*ucm_cmd_table[])(struct ib_ucm_file *file, [IB_USER_CM_CMD_SEND_SIDR_REQ] = ib_ucm_send_sidr_req, [IB_USER_CM_CMD_SEND_SIDR_REP] = ib_ucm_send_sidr_rep, [IB_USER_CM_CMD_EVENT] = ib_ucm_event, + [IB_USER_CM_CMD_INIT_QP_ATTR] = ib_ucm_init_qp_attr, }; static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, @@ -1161,12 +1244,18 @@ static int ib_ucm_close(struct inode *inode, struct file *filp) down(&file->mutex); while (!list_empty(&file->ctxs)) { - ctx = list_entry(file->ctxs.next, struct ib_ucm_context, file_list); - up(&file->mutex); - ib_ucm_destroy_ctx(file, ctx->id); + + down(&ctx_id_mutex); + idr_remove(&ctx_id_table, ctx->id); + up(&ctx_id_mutex); + + ib_destroy_cm_id(ctx->cm_id); + ib_ucm_cleanup_events(ctx); + kfree(ctx); + down(&file->mutex); } up(&file->mutex); diff --git a/drivers/infiniband/core/ucm.h b/drivers/infiniband/core/ucm.h index c8819b928a1ba..f46f37bc1201b 100644 --- a/drivers/infiniband/core/ucm.h +++ b/drivers/infiniband/core/ucm.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -43,8 +44,6 @@ #include <rdma/ib_cm.h> #include <rdma/ib_user_cm.h> -#define IB_UCM_CM_ID_INVALID 0xffffffff - struct ib_ucm_file { struct semaphore mutex; struct file *filp; @@ -58,9 +57,11 @@ struct ib_ucm_context { int id; wait_queue_head_t wait; atomic_t ref; + int events_reported; struct ib_ucm_file *file; struct ib_cm_id *cm_id; + __u64 uid; struct list_head events; /* list of pending events. */ struct list_head file_list; /* member in file ctx list */ @@ -71,16 +72,12 @@ struct ib_ucm_event { struct list_head file_list; /* member in file event list */ struct list_head ctx_list; /* member in ctx event list */ + struct ib_cm_id *cm_id; struct ib_ucm_event_resp resp; void *data; void *info; int data_len; int info_len; - /* - * new connection identifiers needs to be saved until - * userspace can get a handle on them. - */ - struct ib_cm_id *cm_id; }; #endif /* UCM_H */ diff --git a/include/rdma/ib_user_cm.h b/include/rdma/ib_user_cm.h index 72182d16778b5..e4d1654276ad9 100644 --- a/include/rdma/ib_user_cm.h +++ b/include/rdma/ib_user_cm.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -37,7 +38,7 @@ #include <linux/types.h> -#define IB_USER_CM_ABI_VERSION 1 +#define IB_USER_CM_ABI_VERSION 2 enum { IB_USER_CM_CMD_CREATE_ID, @@ -60,6 +61,7 @@ enum { IB_USER_CM_CMD_SEND_SIDR_REP, IB_USER_CM_CMD_EVENT, + IB_USER_CM_CMD_INIT_QP_ATTR, }; /* * command ABI structures. @@ -71,6 +73,7 @@ struct ib_ucm_cmd_hdr { }; struct ib_ucm_create_id { + __u64 uid; __u64 response; }; @@ -79,9 +82,14 @@ struct ib_ucm_create_id_resp { }; struct ib_ucm_destroy_id { + __u64 response; __u32 id; }; +struct ib_ucm_destroy_id_resp { + __u32 events_reported; +}; + struct ib_ucm_attr_id { __u64 response; __u32 id; @@ -94,6 +102,64 @@ struct ib_ucm_attr_id_resp { __be32 remote_id; }; +struct ib_ucm_init_qp_attr { + __u64 response; + __u32 id; + __u32 qp_state; +}; + +struct ib_ucm_ah_attr { + __u8 grh_dgid[16]; + __u32 grh_flow_label; + __u16 dlid; + __u16 reserved; + __u8 grh_sgid_index; + __u8 grh_hop_limit; + __u8 grh_traffic_class; + __u8 sl; + __u8 src_path_bits; + __u8 static_rate; + __u8 is_global; + __u8 port_num; +}; + +struct ib_ucm_init_qp_attr_resp { + __u32 qp_attr_mask; + __u32 qp_state; + __u32 cur_qp_state; + __u32 path_mtu; + __u32 path_mig_state; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + + struct ib_ucm_ah_attr ah_attr; + struct ib_ucm_ah_attr alt_ah_attr; + + /* ib_qp_cap */ + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 en_sqd_async_notify; + __u8 sq_draining; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; +}; + struct ib_ucm_listen { __be64 service_id; __be64 service_mask; @@ -157,6 +223,7 @@ struct ib_ucm_req { }; struct ib_ucm_rep { + __u64 uid; __u64 data; __u32 id; __u32 qpn; @@ -232,7 +299,6 @@ struct ib_ucm_event_get { }; struct ib_ucm_req_event_resp { - __u32 listen_id; /* device */ /* port */ struct ib_ucm_path_rec primary_path; @@ -287,7 +353,6 @@ struct ib_ucm_apr_event_resp { }; struct ib_ucm_sidr_req_event_resp { - __u32 listen_id; /* device */ /* port */ __u16 pkey; @@ -307,6 +372,7 @@ struct ib_ucm_sidr_rep_event_resp { #define IB_UCM_PRES_ALTERNATE 0x08 struct ib_ucm_event_resp { + __u64 uid; __u32 id; __u32 event; __u32 present; -- GitLab From c9fe2b3287498b80781284306064104ef9c8a31a Mon Sep 17 00:00:00 2001 From: Roland Dreier <roland@eddore.topspincom.com> Date: Wed, 7 Sep 2005 09:43:23 -0700 Subject: [PATCH 035/563] [PATCH] IB: really reset QPs When we modify a QP to the RESET state, completely clean up the QP so that it is really and truly reset. Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/hw/mthca/mthca_qp.c | 44 +++++++++++++++++++------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 0164b84d4ec64..c753f7375a5d4 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -220,6 +220,16 @@ static void *get_send_wqe(struct mthca_qp *qp, int n) (PAGE_SIZE - 1)); } +static void mthca_wq_init(struct mthca_wq *wq) +{ + spin_lock_init(&wq->lock); + wq->next_ind = 0; + wq->last_comp = wq->max - 1; + wq->head = 0; + wq->tail = 0; + wq->last = NULL; +} + void mthca_qp_event(struct mthca_dev *dev, u32 qpn, enum ib_event_type event_type) { @@ -833,8 +843,8 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) store_attrs(to_msqp(qp), attr, attr_mask); /* - * If we are moving QP0 to RTR, bring the IB link up; if we - * are moving QP0 to RESET or ERROR, bring the link back down. + * If we moved QP0 to RTR, bring the IB link up; if we moved + * QP0 to RESET or ERROR, bring the link back down. */ if (is_qp0(dev, qp)) { if (cur_state != IB_QPS_RTR && @@ -848,6 +858,26 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) mthca_CLOSE_IB(dev, to_msqp(qp)->port, &status); } + /* + * If we moved a kernel QP to RESET, clean up all old CQ + * entries and reinitialize the QP. + */ + if (!err && new_state == IB_QPS_RESET && !qp->ibqp.uobject) { + mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); + if (qp->ibqp.send_cq != qp->ibqp.recv_cq) + mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); + + mthca_wq_init(&qp->sq); + mthca_wq_init(&qp->rq); + + if (mthca_is_memfree(dev)) { + *qp->sq.db = 0; + *qp->rq.db = 0; + } + } + return err; } @@ -1003,16 +1033,6 @@ static void mthca_free_memfree(struct mthca_dev *dev, } } -static void mthca_wq_init(struct mthca_wq* wq) -{ - spin_lock_init(&wq->lock); - wq->next_ind = 0; - wq->last_comp = wq->max - 1; - wq->head = 0; - wq->tail = 0; - wq->last = NULL; -} - static int mthca_alloc_qp_common(struct mthca_dev *dev, struct mthca_pd *pd, struct mthca_cq *send_cq, -- GitLab From 30a7e8ef13b2ff0db7b15af9afdd12b93783f01e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" <mst@mellanox.co.il> Date: Wed, 7 Sep 2005 09:45:00 -0700 Subject: [PATCH 036/563] [PATCH] IB: Initialize qp->wait Add missing call to init_waitqueue_head(). Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/hw/mthca/mthca_qp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index c753f7375a5d4..bcef06bf15e72 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -1044,6 +1044,7 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, int i; atomic_set(&qp->refcount, 1); + init_waitqueue_head(&qp->wait); qp->state = IB_QPS_RESET; qp->atomic_rd_en = 0; qp->resp_depth = 0; -- GitLab From b5dcbf47e10e568273213a4410daa27c11cdba3a Mon Sep 17 00:00:00 2001 From: Hal Rosenstock <halr@voltaire.com> Date: Wed, 7 Sep 2005 11:03:41 -0700 Subject: [PATCH 037/563] [PATCH] IB: RMPP fixes - Fix payload length of middle RMPP sent segments. Middle payload lengths should be 0 on the send side. (This is perhaps a compliance and should not be an interop issue as middle payload lengths are supposed to be ignored on receive). - Fix length in first segment of multipacket sends (This is a compliance issue but does not affect at least OpenIB to OpenIB RMPP transfers). Signed-off-by: Hal Rosenstock <halr@voltaire.com> Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/core/mad_rmpp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index 43fd805e02659..2bd8b1cc57c4c 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -593,7 +593,8 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(mad_send_wr->total_seg * (sizeof(struct ib_rmpp_mad) - - offsetof(struct ib_rmpp_mad, data))); + offsetof(struct ib_rmpp_mad, data)) - + mad_send_wr->pad); mad_send_wr->sg_list[0].length = sizeof(struct ib_rmpp_mad); } else { mad_send_wr->send_wr.num_sge = 2; @@ -602,6 +603,7 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) mad_send_wr->sg_list[1].length = sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset; mad_send_wr->sg_list[1].lkey = mad_send_wr->sg_list[0].lkey; + rmpp_mad->rmpp_hdr.paylen_newwin = 0; } if (mad_send_wr->seg_num == mad_send_wr->total_seg) { -- GitLab From 17781cd6186cb3472ff34b2d9a15e647bd311e8b Mon Sep 17 00:00:00 2001 From: James Lentini <jlentini@netapp.com> Date: Wed, 7 Sep 2005 12:43:08 -0700 Subject: [PATCH 038/563] [PATCH] IB: clean up user access config options Add a new config option INFINIBAND_USER_MAD to control whether we build ib_umad. Change INFINIBAND_USER_VERBS to INFINIBAND_USER_ACCESS, and have it control ib_ucm and ib_uat as well as ib_uverbs. Signed-off-by: James Lentini <jlentini@netapp.com> Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/Kconfig | 25 ++++++++++++++++++------- drivers/infiniband/core/Makefile | 5 +++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 32cdfb30e9b46..325d502e25cdb 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -8,15 +8,26 @@ config INFINIBAND any protocols you wish to use as well as drivers for your InfiniBand hardware. -config INFINIBAND_USER_VERBS - tristate "InfiniBand userspace verbs support" +config INFINIBAND_USER_MAD + tristate "InfiniBand userspace MAD support" depends on INFINIBAND ---help--- - Userspace InfiniBand verbs support. This is the kernel side - of userspace verbs, which allows userspace processes to - directly access InfiniBand hardware for fast-path - operations. You will also need libibverbs and a hardware - driver library from <http://www.openib.org>. + Userspace InfiniBand Management Datagram (MAD) support. This + is the kernel side of the userspace MAD support, which allows + userspace processes to send and receive MADs. You will also + need libibumad from <http://www.openib.org>. + +config INFINIBAND_USER_ACCESS + tristate "InfiniBand userspace access (verbs and CM)" + depends on INFINIBAND + ---help--- + Userspace InfiniBand access support. This enables the + kernel side of userspace verbs and the userspace + communication manager (CM). This allows userspace processes + to set up connections and directly access InfiniBand + hardware for fast-path operations. You will also need + libibverbs, libibcm and a hardware driver library from + <http://www.openib.org>. source "drivers/infiniband/hw/mthca/Kconfig" diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index 678a7e097f329..ec3353f24b275 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \ - ib_cm.o ib_umad.o ib_ucm.o -obj-$(CONFIG_INFINIBAND_USER_VERBS) += ib_uverbs.o + ib_cm.o +obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o +obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ device.o fmr_pool.o cache.o -- GitLab From 0ba7a3ba6608de6e0c0bfe3009a63d7e0b7ab0ce Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 02:28:47 -0300 Subject: [PATCH 039/563] [CCID3] Avoid unsigned integer overflows in usecs_div Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- net/dccp/ccids/ccid3.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 7bf3b3a91e974..ae0500c79d07d 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -43,12 +43,22 @@ #include "ccid3.h" /* - * Reason for maths with 10 here is to avoid 32 bit overflow when a is big. + * Reason for maths here is to avoid 32 bit overflow when a is big. + * With this we get close to the limit. */ static inline u32 usecs_div(const u32 a, const u32 b) { - const u32 tmp = a * (USEC_PER_SEC / 10); - return b > 20 ? tmp / (b / 10) : tmp; + const u32 div = a < (UINT_MAX / (USEC_PER_SEC / 10)) ? 10 : + a < (UINT_MAX / (USEC_PER_SEC / 50)) ? 50 : + a < (UINT_MAX / (USEC_PER_SEC / 100)) ? 100 : + a < (UINT_MAX / (USEC_PER_SEC / 500)) ? 500 : + a < (UINT_MAX / (USEC_PER_SEC / 1000)) ? 1000 : + a < (UINT_MAX / (USEC_PER_SEC / 5000)) ? 5000 : + a < (UINT_MAX / (USEC_PER_SEC / 10000)) ? 10000 : + a < (UINT_MAX / (USEC_PER_SEC / 50000)) ? 50000 : + 100000; + const u32 tmp = a * (USEC_PER_SEC / div); + return (b >= 2 * div) ? tmp / (b / div) : tmp; } static int ccid3_debug; -- GitLab From 507d37cf269ebbd1b32bcc435fe577e411f73151 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 02:30:07 -0300 Subject: [PATCH 040/563] [CCID] Only call the HC insert_options methods when requested Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- include/linux/dccp.h | 2 ++ net/dccp/ccids/ccid3.c | 5 ++++- net/dccp/options.c | 11 ++++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 007c290f74d45..5e0af0d08a93c 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -433,6 +433,8 @@ struct dccp_sock { struct ccid *dccps_hc_tx_ccid; struct dccp_options_received dccps_options_received; enum dccp_role dccps_role:2; + __u8 dccps_hc_rx_insert_options:1; + __u8 dccps_hc_tx_insert_options:1; }; static inline struct dccp_sock *dccp_sk(const struct sock *sk) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index ae0500c79d07d..37fd9eb8daaf8 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -358,10 +358,12 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, } /* Can we send? if so add options and add to packet history */ - if (rc == 0) + if (rc == 0) { + dp->dccps_hc_tx_insert_options = 1; new_packet->dccphtx_ccval = DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count; + } out: return rc; } @@ -811,6 +813,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) hcrx->ccid3hcrx_pinv = ~0; else hcrx->ccid3hcrx_pinv = 1000000 / hcrx->ccid3hcrx_p; + dp->dccps_hc_rx_insert_options = 1; dccp_send_ack(sk); } diff --git a/net/dccp/options.c b/net/dccp/options.c index 382c5894acb20..7ad2f4266ff9f 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -505,13 +505,18 @@ void dccp_insert_options(struct sock *sk, struct sk_buff *skb) (dp->dccps_hc_rx_ackpkts->dccpap_buf_ackno != DCCP_MAX_SEQNO + 1)) dccp_insert_option_ack_vector(sk, skb); - if (dp->dccps_timestamp_echo != 0) dccp_insert_option_timestamp_echo(sk, skb); } - ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb); - ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb); + if (dp->dccps_hc_rx_insert_options) { + ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb); + dp->dccps_hc_rx_insert_options = 0; + } + if (dp->dccps_hc_tx_insert_options) { + ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb); + dp->dccps_hc_tx_insert_options = 0; + } /* XXX: insert other options when appropriate */ -- GitLab From 27ae543e6f116df66e2b19ff0a3aa1053e4784d8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 02:31:07 -0300 Subject: [PATCH 041/563] [CCID3] Calculate ccid3hcrx_x_recv using usecs_div Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- net/dccp/ccids/ccid3.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 37fd9eb8daaf8..63f897394a1e1 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -779,11 +779,8 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) case TFRC_RSTATE_DATA: { const u32 delta = timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_feedback); - - hcrx->ccid3hcrx_x_recv = (hcrx->ccid3hcrx_bytes_recv * - USEC_PER_SEC); - if (likely(delta > 1)) - hcrx->ccid3hcrx_x_recv /= delta; + hcrx->ccid3hcrx_x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv, + delta); } break; default: -- GitLab From 1c14ac0ae8eb62cbb40af1e31b156994c7d7d3d5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 02:32:01 -0300 Subject: [PATCH 042/563] [DCCP] Give precedence to the biggest ELAPSED_TIME We can get this value in an TIMESTAMP_ECHO and/or in an ELAPSED_TIME option, if receiving both give precendence to the biggest one. In my tests they are very close if not equal at all times, so we may well think about removing the code in CCID3 that inserts this option and leaving this to the core, and perhaps even use just TIMESTAMP_ECHO including the elapsed time. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- net/dccp/options.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/net/dccp/options.c b/net/dccp/options.c index 7ad2f4266ff9f..34b230a008759 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -72,6 +72,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) struct dccp_options_received *opt_recv = &dp->dccps_options_received; unsigned char opt, len; unsigned char *value; + u32 elapsed_time; memset(opt_recv, 0, sizeof(*opt_recv)); @@ -159,18 +160,18 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) (unsigned long long) DCCP_SKB_CB(skb)->dccpd_ack_seq); - if (len > 4) { - if (len == 6) - opt_recv->dccpor_elapsed_time = - ntohs(*(u16 *)(value + 4)); - else - opt_recv->dccpor_elapsed_time = - ntohl(*(u32 *)(value + 4)); - dccp_pr_debug("%sTIMESTAMP_ECHO ELAPSED_TIME=%d\n", - debug_prefix, - opt_recv->dccpor_elapsed_time); - } + if (len == 4) + break; + + if (len == 6) + elapsed_time = ntohs(*(u16 *)(value + 4)); + else + elapsed_time = ntohl(*(u32 *)(value + 4)); + + /* Give precedence to the biggest ELAPSED_TIME */ + if (elapsed_time > opt_recv->dccpor_elapsed_time) + opt_recv->dccpor_elapsed_time = elapsed_time; break; case DCCPO_ELAPSED_TIME: if (len != 2 && len != 4) @@ -180,14 +181,15 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) continue; if (len == 2) - opt_recv->dccpor_elapsed_time = - ntohs(*(u16 *)value); + elapsed_time = ntohs(*(u16 *)value); else - opt_recv->dccpor_elapsed_time = - ntohl(*(u32 *)value); + elapsed_time = ntohl(*(u32 *)value); + + if (elapsed_time > opt_recv->dccpor_elapsed_time) + opt_recv->dccpor_elapsed_time = elapsed_time; dccp_pr_debug("%sELAPSED_TIME=%d\n", debug_prefix, - opt_recv->dccpor_elapsed_time); + elapsed_time); break; /* * From draft-ietf-dccp-spec-11.txt: -- GitLab From 1a28599a2c2781dd6af72f4f84175e2db74d3bb1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 02:32:56 -0300 Subject: [PATCH 043/563] [CCID3] Use ELAPSED_TIME in the HC TX RTT estimation Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- net/dccp/ccids/ccid3.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 63f897394a1e1..86c109e2f2cd8 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -483,7 +483,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) opt_recv = &hctx->ccid3hctx_options_received; - t_elapsed = dp->dccps_options_received.dccpor_elapsed_time; + t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10; x_recv = opt_recv->ccid3or_receive_rate; pinv = opt_recv->ccid3or_loss_event_rate; @@ -509,8 +509,12 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) /* Update RTT */ r_sample = timeval_now_delta(&packet->dccphtx_tstamp); - /* FIXME: */ - // r_sample -= usecs_to_jiffies(t_elapsed * 10); + if (unlikely(r_sample <= t_elapsed)) + LIMIT_NETDEBUG(KERN_WARNING + "%s: r_sample=%uus, t_elapsed=%uus\n", + __FUNCTION__, r_sample, t_elapsed); + else + r_sample -= t_elapsed; /* Update RTT estimate by * If (No feedback recv) -- GitLab From b3a3077d963fc54a25be26e2e84fe9f4327c1e12 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 02:34:10 -0300 Subject: [PATCH 044/563] [CCID3] Make the ccid3hcrx_rtt calc look more like the ccid3hctx_rtt one Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- net/dccp/ccids/ccid3.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 86c109e2f2cd8..0804b3e435c87 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -962,7 +962,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) struct dccp_rx_hist_entry *packet; struct timeval now; u8 win_count; - u32 p_prev; + u32 p_prev, r_sample, t_elapsed; int ins; if (hcrx == NULL) @@ -982,9 +982,23 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) break; p_prev = hcrx->ccid3hcrx_rtt; do_gettimeofday(&now); - hcrx->ccid3hcrx_rtt = timeval_usecs(&now) - - (opt_recv->dccpor_timestamp_echo - - opt_recv->dccpor_elapsed_time) * 10; + timeval_sub_usecs(&now, opt_recv->dccpor_timestamp_echo * 10); + r_sample = timeval_usecs(&now); + t_elapsed = opt_recv->dccpor_elapsed_time * 10; + + if (unlikely(r_sample <= t_elapsed)) + LIMIT_NETDEBUG(KERN_WARNING + "%s: r_sample=%uus, t_elapsed=%uus\n", + __FUNCTION__, r_sample, t_elapsed); + else + r_sample -= t_elapsed; + + if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA) + hcrx->ccid3hcrx_rtt = r_sample; + else + hcrx->ccid3hcrx_rtt = (hcrx->ccid3hcrx_rtt * 9) / 10 + + r_sample / 10; + if (p_prev != hcrx->ccid3hcrx_rtt) ccid3_pr_debug("%s, New RTT=%luus, elapsed time=%u\n", dccp_role(sk), hcrx->ccid3hcrx_rtt, -- GitLab From 954ee31f366fabe53fb450482789258fe552f40b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 02:37:05 -0300 Subject: [PATCH 045/563] [CCID3] Initialize more fields in ccid3_hc_rx_init The initialization of ccid3hcrx_rtt to 5ms is just a bandaid, I'll continue auditing the CCID3 HC rx codebase to fix this properly, probably I'll add a feedback timer as suggested in the CCID3 draft. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- net/dccp/ccids/ccid3.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 0804b3e435c87..145aafafe4e27 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -1100,11 +1100,9 @@ static int ccid3_hc_rx_init(struct sock *sk) hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA; INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist); INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist); - /* - * XXX this seems to be paranoid, need to think more about this, for - * now start with something different than zero. -acme - */ - hcrx->ccid3hcrx_rtt = USEC_PER_SEC / 5; + do_gettimeofday(&hcrx->ccid3hcrx_tstamp_last_ack); + hcrx->ccid3hcrx_tstamp_last_feedback = hcrx->ccid3hcrx_tstamp_last_ack; + hcrx->ccid3hcrx_rtt = 5000; /* XXX 5ms for now... */ return 0; } -- GitLab From b0e567806d16586629468c824dfb2e71155df7da Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 02:38:35 -0300 Subject: [PATCH 046/563] [DCCP] Introduce dccp_timestamp To start the timestamps with 0.0ms, easing the integer maths in the CCIDs, this probably will be reworked to use the to be introduced struct timeval_offset infrastructure out of skb_get_timestamp, etc. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- include/linux/dccp.h | 1 + net/dccp/ccids/ccid3.c | 27 ++++++++--------- net/dccp/ccids/ccid3.h | 2 +- net/dccp/ccids/lib/packet_history.h | 3 +- net/dccp/dccp.h | 16 +++------- net/dccp/input.c | 4 +-- net/dccp/ipv4.c | 1 + net/dccp/minisocks.c | 1 + net/dccp/options.c | 45 ++++++++++++++++++++++------- 9 files changed, 61 insertions(+), 39 deletions(-) diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 5e0af0d08a93c..8bf4bacb5051a 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -432,6 +432,7 @@ struct dccp_sock { struct ccid *dccps_hc_rx_ccid; struct ccid *dccps_hc_tx_ccid; struct dccp_options_received dccps_options_received; + struct timeval dccps_epoch; enum dccp_role dccps_role:2; __u8 dccps_hc_rx_insert_options:1; __u8 dccps_hc_tx_insert_options:1; diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 145aafafe4e27..348e6fb262c3b 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -169,7 +169,7 @@ static void ccid3_hc_tx_update_x(struct sock *sk) } else { struct timeval now; - do_gettimeofday(&now); + dccp_timestamp(sk, &now); if (timeval_delta(&now, &hctx->ccid3hctx_t_ld) >= hctx->ccid3hctx_rtt) { hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_recv, @@ -317,7 +317,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, new_packet); } - do_gettimeofday(&now); + dccp_timestamp(sk, &now); switch (hctx->ccid3hctx_state) { case TFRC_SSTATE_NO_SENT: @@ -382,7 +382,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len) return; } - do_gettimeofday(&now); + dccp_timestamp(sk, &now); /* check if we have sent a data packet */ if (len > 0) { @@ -461,6 +461,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; struct ccid3_options_received *opt_recv; struct dccp_tx_hist_entry *packet; + struct timeval now; unsigned long next_tmout; u32 t_elapsed; u32 pinv; @@ -508,7 +509,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) } /* Update RTT */ - r_sample = timeval_now_delta(&packet->dccphtx_tstamp); + dccp_timestamp(sk, &now); + r_sample = timeval_delta(&now, &packet->dccphtx_tstamp); if (unlikely(r_sample <= t_elapsed)) LIMIT_NETDEBUG(KERN_WARNING "%s: r_sample=%uus, t_elapsed=%uus\n", @@ -774,7 +776,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); - do_gettimeofday(&now); + dccp_timestamp(sk, &now); switch (hcrx->ccid3hcrx_state) { case TFRC_RSTATE_NO_DATA: @@ -903,10 +905,9 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk) if (rtt == 0) rtt = 1; - delta = timeval_now_delta(&hcrx->ccid3hcrx_tstamp_last_feedback); - x_recv = hcrx->ccid3hcrx_bytes_recv * USEC_PER_SEC; - if (likely(delta > 1)) - x_recv /= delta; + dccp_timestamp(sk, &tstamp); + delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback); + x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv, delta); tmp1 = (u64)x_recv * (u64)rtt; do_div(tmp1,10000000); @@ -981,7 +982,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) if (opt_recv->dccpor_timestamp_echo == 0) break; p_prev = hcrx->ccid3hcrx_rtt; - do_gettimeofday(&now); + dccp_timestamp(sk, &now); timeval_sub_usecs(&now, opt_recv->dccpor_timestamp_echo * 10); r_sample = timeval_usecs(&now); t_elapsed = opt_recv->dccpor_elapsed_time * 10; @@ -1013,7 +1014,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) return; } - packet = dccp_rx_hist_entry_new(ccid3_rx_hist, opt_recv->dccpor_ndp, + packet = dccp_rx_hist_entry_new(ccid3_rx_hist, sk, opt_recv->dccpor_ndp, skb, SLAB_ATOMIC); if (packet == NULL) { ccid3_pr_debug("%s, sk=%p, Not enough mem to add rx packet " @@ -1045,7 +1046,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) if (ins != 0) break; - do_gettimeofday(&now); + dccp_timestamp(sk, &now); if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) >= hcrx->ccid3hcrx_rtt) { hcrx->ccid3hcrx_tstamp_last_ack = now; @@ -1100,7 +1101,7 @@ static int ccid3_hc_rx_init(struct sock *sk) hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA; INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist); INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist); - do_gettimeofday(&hcrx->ccid3hcrx_tstamp_last_ack); + dccp_timestamp(sk, &hcrx->ccid3hcrx_tstamp_last_ack); hcrx->ccid3hcrx_tstamp_last_feedback = hcrx->ccid3hcrx_tstamp_last_ack; hcrx->ccid3hcrx_rtt = 5000; /* XXX 5ms for now... */ return 0; diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index ee8cbace6630a..58be6125b695d 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -115,7 +115,7 @@ struct ccid3_hc_rx_sock { u64 ccid3hcrx_seqno_last_counter:48, ccid3hcrx_state:8, ccid3hcrx_last_counter:4; - unsigned long ccid3hcrx_rtt; + u32 ccid3hcrx_rtt; u32 ccid3hcrx_p; u32 ccid3hcrx_bytes_recv; struct timeval ccid3hcrx_tstamp_last_feedback; diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h index fb90a91aa93d6..b375ebdb7dcfb 100644 --- a/net/dccp/ccids/lib/packet_history.h +++ b/net/dccp/ccids/lib/packet_history.h @@ -134,6 +134,7 @@ static inline struct dccp_tx_hist_entry * static inline struct dccp_rx_hist_entry * dccp_rx_hist_entry_new(struct dccp_rx_hist *hist, + const struct sock *sk, const u32 ndp, const struct sk_buff *skb, const unsigned int __nocast prio) @@ -148,7 +149,7 @@ static inline struct dccp_rx_hist_entry * entry->dccphrx_ccval = dh->dccph_ccval; entry->dccphrx_type = dh->dccph_type; entry->dccphrx_ndp = ndp; - do_gettimeofday(&(entry->dccphrx_tstamp)); + dccp_timestamp(sk, &entry->dccphrx_tstamp); } return entry; diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 33456c0d5937c..95c4630b3b184 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -426,10 +426,13 @@ extern struct dccp_ackpkts * dccp_ackpkts_alloc(unsigned int len, const unsigned int __nocast priority); extern void dccp_ackpkts_free(struct dccp_ackpkts *ap); -extern int dccp_ackpkts_add(struct dccp_ackpkts *ap, u64 ackno, u8 state); +extern int dccp_ackpkts_add(struct dccp_ackpkts *ap, const struct sock *sk, + u64 ackno, u8 state); extern void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap, struct sock *sk, u64 ackno); +extern void dccp_timestamp(const struct sock *sk, struct timeval *tv); + static inline suseconds_t timeval_usecs(const struct timeval *tv) { return tv->tv_sec * USEC_PER_SEC + tv->tv_usec; @@ -468,17 +471,6 @@ static inline void timeval_sub_usecs(struct timeval *tv, } } -/* - * Returns the difference in usecs between timeval - * passed in and current time - */ -static inline suseconds_t timeval_now_delta(const struct timeval *tv) -{ - struct timeval now; - do_gettimeofday(&now); - return timeval_delta(&now, tv); -} - #ifdef CONFIG_IP_DCCP_DEBUG extern void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, int len); diff --git a/net/dccp/input.c b/net/dccp/input.c index ef29cef1dafe2..c60bc3433f5ea 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -170,7 +170,7 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, if (dp->dccps_options.dccpo_send_ack_vector) { struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts; - if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts, + if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts, sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_ACKPKTS_STATE_RECEIVED)) { LIMIT_NETDEBUG(KERN_WARNING "DCCP: acknowledgeable " @@ -498,7 +498,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, * DCCP_ACKPKTS_STATE_ECN_MARKED */ if (dp->dccps_options.dccpo_send_ack_vector) { - if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts, + if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts, sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_ACKPKTS_STATE_RECEIVED)) goto discard; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 3fc75dbee4b8e..fee9a8c3777b3 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -1243,6 +1243,7 @@ static int dccp_v4_init_sock(struct sock *sk) static int dccp_ctl_socket_init = 1; dccp_options_init(&dp->dccps_options); + do_gettimeofday(&dp->dccps_epoch); if (dp->dccps_options.dccpo_send_ack_vector) { dp->dccps_hc_rx_ackpkts = diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index ce5dff4ac22ea..18461bc04cbef 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -96,6 +96,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk, newdp->dccps_hc_rx_ackpkts = NULL; newdp->dccps_role = DCCP_ROLE_SERVER; newicsk->icsk_rto = DCCP_TIMEOUT_INIT; + do_gettimeofday(&newdp->dccps_epoch); if (newdp->dccps_options.dccpo_send_ack_vector) { newdp->dccps_hc_rx_ackpkts = diff --git a/net/dccp/options.c b/net/dccp/options.c index 34b230a008759..d4c4242d8dd7c 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -140,7 +140,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) opt_recv->dccpor_timestamp = ntohl(*(u32 *)value); dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; - do_gettimeofday(&dp->dccps_timestamp_time); + dccp_timestamp(sk, &dp->dccps_timestamp_time); dccp_pr_debug("%sTIMESTAMP=%u, ackno=%llu\n", debug_prefix, opt_recv->dccpor_timestamp, @@ -361,9 +361,13 @@ static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb) #endif struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts; int len = ap->dccpap_buf_vector_len + 2; - const u32 elapsed_time = timeval_now_delta(&ap->dccpap_time) / 10; + struct timeval now; + u32 elapsed_time; unsigned char *to, *from; + dccp_timestamp(sk, &now); + elapsed_time = timeval_delta(&now, &ap->dccpap_time) / 10; + if (elapsed_time != 0) dccp_insert_option_elapsed_time(sk, skb, elapsed_time); @@ -428,13 +432,29 @@ static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb) (unsigned long long) ap->dccpap_ack_ackno); } +void dccp_timestamp(const struct sock *sk, struct timeval *tv) +{ + const struct dccp_sock *dp = dccp_sk(sk); + + do_gettimeofday(tv); + tv->tv_sec -= dp->dccps_epoch.tv_sec; + tv->tv_usec -= dp->dccps_epoch.tv_usec; + + while (tv->tv_usec < 0) { + tv->tv_sec--; + tv->tv_usec += USEC_PER_SEC; + } +} + +EXPORT_SYMBOL_GPL(dccp_timestamp); + void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) { struct timeval tv; u32 now; - do_gettimeofday(&tv); - now = (tv.tv_sec * USEC_PER_SEC + tv.tv_usec) / 10; + dccp_timestamp(sk, &tv); + now = timeval_usecs(&tv) / 10; /* yes this will overflow but that is the point as we want a * 10 usec 32 bit timer which mean it wraps every 11.9 hours */ @@ -452,13 +472,17 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk, const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? "CLIENT TX opt: " : "server TX opt: "; #endif + struct timeval now; u32 tstamp_echo; - const u32 elapsed_time = - timeval_now_delta(&dp->dccps_timestamp_time) / 10; - const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); - const int len = 6 + elapsed_time_len; + u32 elapsed_time; + int len, elapsed_time_len; unsigned char *to; + dccp_timestamp(sk, &now); + elapsed_time = timeval_delta(&now, &dp->dccps_timestamp_time) / 10; + elapsed_time_len = dccp_elapsed_time_len(elapsed_time); + len = 6 + elapsed_time_len; + if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " "timestamp echo!\n"); @@ -623,7 +647,8 @@ static inline int dccp_ackpkts_set_buf_head_state(struct dccp_ackpkts *ap, /* * Implements the draft-ietf-dccp-spec-11.txt Appendix A */ -int dccp_ackpkts_add(struct dccp_ackpkts *ap, u64 ackno, u8 state) +int dccp_ackpkts_add(struct dccp_ackpkts *ap, const struct sock *sk, + u64 ackno, u8 state) { /* * Check at the right places if the buffer is full, if it is, tell the @@ -704,7 +729,7 @@ int dccp_ackpkts_add(struct dccp_ackpkts *ap, u64 ackno, u8 state) } ap->dccpap_buf_ackno = ackno; - do_gettimeofday(&ap->dccpap_time); + dccp_timestamp(sk, &ap->dccpap_time); out: dccp_pr_debug(""); dccp_ackpkts_print(ap); -- GitLab From 59725dc2a2e86a03bbf97976ede3bdc6f95bba92 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 02:40:58 -0300 Subject: [PATCH 047/563] [CCID3] Introduce ccid3_hc_[rt]x_sk() for overal consistency Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- net/dccp/ccids/ccid3.c | 70 +++++++++++++++++------------------------- net/dccp/ccids/ccid3.h | 12 +++++--- 2 files changed, 37 insertions(+), 45 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 348e6fb262c3b..ea30012dd1954 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -112,8 +112,7 @@ static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state) static inline void ccid3_hc_tx_set_state(struct sock *sk, enum ccid3_hc_tx_states state) { - struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; + struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state; ccid3_pr_debug("%s(%p) %-8.8s -> %s\n", @@ -154,8 +153,7 @@ static inline void ccid3_calc_new_delta(struct ccid3_hc_tx_sock *hctx) */ static void ccid3_hc_tx_update_x(struct sock *sk) { - struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; + struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); /* To avoid large error in calcX */ if (hctx->ccid3hctx_p >= TFRC_SMALLEST_P) { @@ -184,9 +182,8 @@ static void ccid3_hc_tx_update_x(struct sock *sk) static void ccid3_hc_tx_no_feedback_timer(unsigned long data) { struct sock *sk = (struct sock *)data; - struct dccp_sock *dp = dccp_sk(sk); unsigned long next_tmout = 0; - struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; + struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); bh_lock_sock(sk); if (sock_owned_by_user(sk)) { @@ -284,7 +281,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb, int len) { struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; + struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct dccp_tx_hist_entry *new_packet; struct timeval now; long delay; @@ -370,8 +367,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len) { - struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; + const struct dccp_sock *dp = dccp_sk(sk); + struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct timeval now; BUG_ON(hctx == NULL); @@ -457,8 +454,8 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len) static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) { - struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; + const struct dccp_sock *dp = dccp_sk(sk); + struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct ccid3_options_received *opt_recv; struct dccp_tx_hist_entry *packet; struct timeval now; @@ -609,8 +606,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) static void ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb) { - const struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; + struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); if (hctx == NULL || !(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)) @@ -624,8 +620,8 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, unsigned char *value) { int rc = 0; - struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; + const struct dccp_sock *dp = dccp_sk(sk); + struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct ccid3_options_received *opt_recv; if (hctx == NULL) @@ -688,11 +684,11 @@ static int ccid3_hc_tx_init(struct sock *sk) ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); - hctx = dp->dccps_hc_tx_ccid_private = kmalloc(sizeof(*hctx), - gfp_any()); - if (hctx == NULL) + dp->dccps_hc_tx_ccid_private = kmalloc(sizeof(*hctx), gfp_any()); + if (dp->dccps_hc_tx_ccid_private == NULL) return -ENOMEM; + hctx = ccid3_hc_tx_sk(sk); memset(hctx, 0, sizeof(*hctx)); if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE && @@ -714,7 +710,7 @@ static int ccid3_hc_tx_init(struct sock *sk) static void ccid3_hc_tx_exit(struct sock *sk) { struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; + struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); BUG_ON(hctx == NULL); @@ -756,8 +752,7 @@ static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state) static inline void ccid3_hc_rx_set_state(struct sock *sk, enum ccid3_hc_rx_states state) { - struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; + struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state; ccid3_pr_debug("%s(%p) %-8.8s -> %s\n", @@ -769,8 +764,8 @@ static inline void ccid3_hc_rx_set_state(struct sock *sk, static void ccid3_hc_rx_send_feedback(struct sock *sk) { + struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; struct dccp_rx_hist_entry *packet; struct timeval now; @@ -822,9 +817,8 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) { - const struct dccp_sock *dp = dccp_sk(sk); + struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); u32 x_recv, pinv; - struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; if (hcrx == NULL || !(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)) @@ -853,8 +847,7 @@ static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) static u32 ccid3_hc_rx_calc_first_li(struct sock *sk) { - struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; + struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); struct dccp_rx_hist_entry *entry, *next, *tail = NULL; u32 rtt, delta, x_recv, fval, p, tmp2; struct timeval tstamp = { 0, }; @@ -926,8 +919,7 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk) static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss) { - struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; + struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); if (seq_loss != DCCP_MAX_SEQNO + 1 && list_empty(&hcrx->ccid3hcrx_li_hist)) { @@ -945,8 +937,7 @@ static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss) static void ccid3_hc_rx_detect_loss(struct sock *sk) { - struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; + struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); u8 win_loss; const u64 seq_loss = dccp_rx_hist_detect_loss(&hcrx->ccid3hcrx_hist, &hcrx->ccid3hcrx_li_hist, @@ -957,8 +948,7 @@ static void ccid3_hc_rx_detect_loss(struct sock *sk) static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) { - struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; + struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); const struct dccp_options_received *opt_recv; struct dccp_rx_hist_entry *packet; struct timeval now; @@ -972,7 +962,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) BUG_ON(!(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA || hcrx->ccid3hcrx_state == TFRC_RSTATE_DATA)); - opt_recv = &dp->dccps_options_received; + opt_recv = &dccp_sk(sk)->dccps_options_received; switch (DCCP_SKB_CB(skb)->dccpd_type) { case DCCP_PKT_ACK: @@ -1085,11 +1075,11 @@ static int ccid3_hc_rx_init(struct sock *sk) ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); - hcrx = dp->dccps_hc_rx_ccid_private = kmalloc(sizeof(*hcrx), - gfp_any()); - if (hcrx == NULL) + dp->dccps_hc_rx_ccid_private = kmalloc(sizeof(*hcrx), gfp_any()); + if (dp->dccps_hc_rx_ccid_private == NULL) return -ENOMEM; + hcrx = ccid3_hc_rx_sk(sk); memset(hcrx, 0, sizeof(*hcrx)); if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE && @@ -1109,8 +1099,8 @@ static int ccid3_hc_rx_init(struct sock *sk) static void ccid3_hc_rx_exit(struct sock *sk) { + struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); @@ -1131,8 +1121,7 @@ static void ccid3_hc_rx_exit(struct sock *sk) static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) { - const struct dccp_sock *dp = dccp_sk(sk); - const struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; + const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); if (hcrx == NULL) return; @@ -1144,8 +1133,7 @@ static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) { - const struct dccp_sock *dp = dccp_sk(sk); - const struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private; + const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); if (hctx == NULL) return; diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 58be6125b695d..d16f00d784f39 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -128,10 +128,14 @@ struct ccid3_hc_rx_sock { u32 ccid3hcrx_x_recv; }; -#define ccid3_hc_tx_field(s,field) (s->dccps_hc_tx_ccid_private == NULL ? 0 : \ - ((struct ccid3_hc_tx_sock *)s->dccps_hc_tx_ccid_private)->ccid3hctx_##field) +static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk) +{ + return dccp_sk(sk)->dccps_hc_tx_ccid_private; +} -#define ccid3_hc_rx_field(s,field) (s->dccps_hc_rx_ccid_private == NULL ? 0 : \ - ((struct ccid3_hc_rx_sock *)s->dccps_hc_rx_ccid_private)->ccid3hcrx_##field) +static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk) +{ + return dccp_sk(sk)->dccps_hc_rx_ccid_private; +} #endif /* _DCCP_CCID3_H_ */ -- GitLab From 9c2c389307c03a35672c80725ccf7968656d87ef Mon Sep 17 00:00:00 2001 From: Russell King <rmk@dyn-67.arm.linux.org.uk> Date: Fri, 9 Sep 2005 11:12:51 +0100 Subject: [PATCH 048/563] [ARM] Add memory type based allocation syscalls Add syscall numbers and syscall table entries for mbind, set_mempolicy and get_mempolicy. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/kernel/calls.S | 5 ++++- include/asm-arm/unistd.h | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index db07ce42b3b2c..cc89a73ada6f1 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -10,7 +10,7 @@ * This file is included twice in entry-common.S */ #ifndef NR_syscalls -#define NR_syscalls 320 +#define NR_syscalls 328 #else __syscall_start: @@ -333,6 +333,9 @@ __syscall_start: .long sys_inotify_init .long sys_inotify_add_watch .long sys_inotify_rm_watch + .long sys_mbind +/* 320 */ .long sys_get_mempolicy + .long sys_set_mempolicy __syscall_end: .rept NR_syscalls - (__syscall_end - __syscall_start) / 4 diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index 278de61224d1c..c49df635a80f1 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -355,6 +355,9 @@ #define __NR_inotify_init (__NR_SYSCALL_BASE+316) #define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317) #define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318) +#define __NR_mbind (__NR_SYSCALL_BASE+319) +#define __NR_get_mempolicy (__NR_SYSCALL_BASE+320) +#define __NR_set_mempolicy (__NR_SYSCALL_BASE+321) /* * The following SWIs are ARM private. -- GitLab From 35efb606e544403835df48cd240441a8e089c80b Mon Sep 17 00:00:00 2001 From: Russell King <rmk@dyn-67.arm.linux.org.uk> Date: Fri, 9 Sep 2005 15:57:17 +0100 Subject: [PATCH 049/563] [ARM] Fix typo in arch/arm/Kconfig.debug It's called printch, not printchar Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 45a5709eaaa45..5d3acff8c596e 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -53,7 +53,7 @@ config DEBUG_LL bool "Kernel low-level debugging functions" depends on DEBUG_KERNEL help - Say Y here to include definitions of printascii, printchar, printhex + Say Y here to include definitions of printascii, printch, printhex in the kernel. This is helpful if you are debugging code that executes before the console is initialized. -- GitLab From 6f0d618f0e9b8025d1c3531e82d7cc8455e79394 Mon Sep 17 00:00:00 2001 From: Russell King <rmk@dyn-67.arm.linux.org.uk> Date: Fri, 9 Sep 2005 16:17:58 +0100 Subject: [PATCH 050/563] [SERIAL] Spelling fix in 8250.c Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- drivers/serial/8250.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 5b65e208893bc..4d75cdfa0a0af 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -864,7 +864,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) /* * We're pretty sure there's a port here. Lets find out what * type of port it is. The IIR top two bits allows us to find - * out if its 8250 or 16450, 16550, 16550A or later. This + * out if it's 8250 or 16450, 16550, 16550A or later. This * determines what we test for next. * * We also initialise the EFR (if any) to zero for later. The -- GitLab From 86feeaa8120bb1b0ab21efed49e9754039395ef1 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 19:28:28 +0200 Subject: [PATCH 051/563] kbuild: full dependency check on asm-offsets.h Building asm-offsets.h has been moved to a seperate Kbuild file located in the top-level directory. This allow us to share the functionality across the architectures. The old rules in architecture specific Makefiles will die in subsequent patches. Furhtermore the usual kbuild dependency tracking is now used when deciding to rebuild asm-offsets.s. So we no longer risk to fail a rebuild caused by asm-offsets.c dependencies being touched. With this common rule-set we now force the same name across all architectures. Following patches will fix the rest. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- Kbuild | 41 +++++++++++++++++++++++++++ Makefile | 39 +++++++------------------ arch/i386/Makefile | 9 ------ arch/i386/kernel/head.S | 2 +- arch/i386/kernel/vsyscall-sigreturn.S | 2 +- arch/i386/kernel/vsyscall.lds.S | 2 +- arch/i386/power/swsusp.S | 2 +- include/asm-i386/thread_info.h | 2 +- 8 files changed, 57 insertions(+), 42 deletions(-) create mode 100644 Kbuild diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000000000..197ece85034ba --- /dev/null +++ b/Kbuild @@ -0,0 +1,41 @@ +# +# Kbuild for top-level directory of the kernel +# This file takes care of the following: +# 1) Generate asm-offsets.h + +##### +# 1) Generate asm-offsets.h +# + +offsets-file := include/asm-$(ARCH)/asm-offsets.h + +always := $(offsets-file) +targets := $(offsets-file) +targets += arch/$(ARCH)/kernel/asm-offsets.s + +quiet_cmd_offsets = GEN $@ +define cmd_offsets + cat $< | \ + (set -e; \ + echo "#ifndef __ASM_OFFSETS_H__"; \ + echo "#define __ASM_OFFSETS_H__"; \ + echo "/*"; \ + echo " * DO NOT MODIFY."; \ + echo " *"; \ + echo " * This file was generated by $(srctree)/Kbuild"; \ + echo " *"; \ + echo " */"; \ + echo ""; \ + sed -ne "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"; \ + echo ""; \ + echo "#endif" ) > $@ +endef + +# We use internal kbuild rules to avoid the "is up to date" message from make +arch/$(ARCH)/kernel/asm-offsets.s: arch/$(ARCH)/kernel/asm-offsets.c FORCE + $(Q)mkdir -p $(dir $@) + $(call if_changed_dep,cc_s_c) + +$(srctree)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild + $(call cmd,offsets) + diff --git a/Makefile b/Makefile index 63e5c9f0bc7ad..2402430c87e66 100644 --- a/Makefile +++ b/Makefile @@ -776,14 +776,14 @@ $(vmlinux-dirs): prepare-all scripts # A multi level approach is used. prepare1 is updated first, then prepare0. # prepare-all is the collection point for the prepare targets. -.PHONY: prepare-all prepare prepare0 prepare1 prepare2 +.PHONY: prepare-all prepare prepare0 prepare1 prepare2 prepare3 -# prepare2 is used to check if we are building in a separate output directory, +# prepare3 is used to check if we are building in a separate output directory, # and if so do: # 1) Check that make has not been executed in the kernel src $(srctree) # 2) Create the include2 directory, used for the second asm symlink -prepare2: +prepare3: ifneq ($(KBUILD_SRC),) @echo ' Using $(srctree) as source for kernel' $(Q)if [ -f $(srctree)/.config ]; then \ @@ -795,18 +795,21 @@ ifneq ($(KBUILD_SRC),) $(Q)ln -fsn $(srctree)/include/asm-$(ARCH) include2/asm endif -# prepare1 creates a makefile if using a separate output directory -prepare1: prepare2 outputmakefile +# prepare2 creates a makefile if using a separate output directory +prepare2: prepare3 outputmakefile -prepare0: prepare1 include/linux/version.h include/asm \ +prepare1: prepare2 include/linux/version.h include/asm \ include/config/MARKER ifneq ($(KBUILD_MODULES),) $(Q)rm -rf $(MODVERDIR) $(Q)mkdir -p $(MODVERDIR) endif +prepare0: prepare prepare1 FORCE + $(Q)$(MAKE) $(build)=$(srctree) + # All the preparing.. -prepare-all: prepare0 prepare +prepare-all: prepare0 # Leave this as default for preprocessing vmlinux.lds.S, which is now # done in arch/$(ARCH)/kernel/Makefile @@ -949,26 +952,6 @@ modules modules_install: FORCE endif # CONFIG_MODULES -# Generate asm-offsets.h -# --------------------------------------------------------------------------- - -define filechk_gen-asm-offsets - (set -e; \ - echo "#ifndef __ASM_OFFSETS_H__"; \ - echo "#define __ASM_OFFSETS_H__"; \ - echo "/*"; \ - echo " * DO NOT MODIFY."; \ - echo " *"; \ - echo " * This file was generated by arch/$(ARCH)/Makefile"; \ - echo " *"; \ - echo " */"; \ - echo ""; \ - sed -ne "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"; \ - echo ""; \ - echo "#endif" ) -endef - - ### # Cleaning is done on three levels. # make clean Delete most generated files @@ -991,7 +974,7 @@ MRPROPER_FILES += .config .config.old include/asm .version \ # clean: rm-dirs := $(CLEAN_DIRS) clean: rm-files := $(CLEAN_FILES) -clean-dirs := $(addprefix _clean_,$(vmlinux-alldirs)) +clean-dirs := $(addprefix _clean_,$(srctree) $(vmlinux-alldirs)) .PHONY: $(clean-dirs) clean archclean $(clean-dirs): diff --git a/arch/i386/Makefile b/arch/i386/Makefile index bf7c9ba709f32..09951990a6226 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -156,15 +156,6 @@ install: vmlinux install kernel_install: $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install -prepare: include/asm-$(ARCH)/asm_offsets.h -CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h - -arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - archclean: $(Q)$(MAKE) $(clean)=arch/i386/boot diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index 0480ca9e9e577..e437fb367498c 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -17,7 +17,7 @@ #include <asm/desc.h> #include <asm/cache.h> #include <asm/thread_info.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/setup.h> /* diff --git a/arch/i386/kernel/vsyscall-sigreturn.S b/arch/i386/kernel/vsyscall-sigreturn.S index 68afa50dd7cf7..fadb5bc3c3743 100644 --- a/arch/i386/kernel/vsyscall-sigreturn.S +++ b/arch/i386/kernel/vsyscall-sigreturn.S @@ -7,7 +7,7 @@ */ #include <asm/unistd.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> /* XXX diff --git a/arch/i386/kernel/vsyscall.lds.S b/arch/i386/kernel/vsyscall.lds.S index a7977707c8e50..98699ca6e52d7 100644 --- a/arch/i386/kernel/vsyscall.lds.S +++ b/arch/i386/kernel/vsyscall.lds.S @@ -3,7 +3,7 @@ * object prelinked to its virtual address, and with only one read-only * segment (that fits in one page). This script controls its layout. */ -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> SECTIONS { diff --git a/arch/i386/power/swsusp.S b/arch/i386/power/swsusp.S index c4105286ff26f..c893b897217fa 100644 --- a/arch/i386/power/swsusp.S +++ b/arch/i386/power/swsusp.S @@ -12,7 +12,7 @@ #include <linux/linkage.h> #include <asm/segment.h> #include <asm/page.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> .text diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h index e2cb9fa6f563d..8fbf791651bf8 100644 --- a/include/asm-i386/thread_info.h +++ b/include/asm-i386/thread_info.h @@ -48,7 +48,7 @@ struct thread_info { #else /* !__ASSEMBLY__ */ -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #endif -- GitLab From 9b9eb8c06177f07657ad35440b56cbf68e1d253b Mon Sep 17 00:00:00 2001 From: Russell King <rmk@dyn-67.arm.linux.org.uk> Date: Fri, 9 Sep 2005 18:35:12 +0100 Subject: [PATCH 052/563] [ARM] sys_mbind needs wrapping sys_mbind is a 6-arg syscall, hence needs wrapping to save the sixth argument. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/kernel/calls.S | 2 +- arch/arm/kernel/entry-common.S | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index cc89a73ada6f1..949ec4427f216 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -333,7 +333,7 @@ __syscall_start: .long sys_inotify_init .long sys_inotify_add_watch .long sys_inotify_rm_watch - .long sys_mbind + .long sys_mbind_wrapper /* 320 */ .long sys_get_mempolicy .long sys_set_mempolicy __syscall_end: diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 6281d488ac975..db302c6e53439 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -269,6 +269,10 @@ sys_arm_fadvise64_64_wrapper: str r5, [sp, #4] @ push r5 to stack b sys_arm_fadvise64_64 +sys_mbind_wrapper: + str r5, [sp, #4] + b sys_mbind + /* * Note: off_4k (r5) is always units of 4K. If we can't do the requested * offset, we return EINVAL. -- GitLab From aa6c2e794f7e1f54dc52c84471c750327fa21ccd Mon Sep 17 00:00:00 2001 From: Richard Purdie <rpurdie@rpsys.net> Date: Fri, 9 Sep 2005 18:54:03 +0100 Subject: [PATCH 053/563] [ARM] 2893/1: [MMC] Update corgi to use the new mmc delayed detection function Patch from Richard Purdie We can remove this timer and its associated code from the corgi platform code now mmc_detect_change() and the pxamci code support an optional delay. Signed-off-by: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/mach-pxa/corgi.c | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 29185acdd9e1e..07b5dd4535654 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -131,27 +131,12 @@ static struct platform_device corgits_device = { /* * MMC/SD Device * - * The card detect interrupt isn't debounced so we delay it by HZ/4 + * The card detect interrupt isn't debounced so we delay it by 250ms * to give the card a chance to fully insert/eject. */ -static struct mmc_detect { - struct timer_list detect_timer; - void *devid; -} mmc_detect; +static struct pxamci_platform_data corgi_mci_platform_data; -static void mmc_detect_callback(unsigned long data) -{ - mmc_detect_change(mmc_detect.devid); -} - -static irqreturn_t corgi_mmc_detect_int(int irq, void *devid, struct pt_regs *regs) -{ - mmc_detect.devid=devid; - mod_timer(&mmc_detect.detect_timer, jiffies + HZ/4); - return IRQ_HANDLED; -} - -static int corgi_mci_init(struct device *dev, irqreturn_t (*unused_detect_int)(int, void *, struct pt_regs *), void *data) +static int corgi_mci_init(struct device *dev, irqreturn_t (*corgi_detect_int)(int, void *, struct pt_regs *), void *data) { int err; @@ -161,11 +146,9 @@ static int corgi_mci_init(struct device *dev, irqreturn_t (*unused_detect_int)(i pxa_gpio_mode(CORGI_GPIO_nSD_DETECT | GPIO_IN); pxa_gpio_mode(CORGI_GPIO_SD_PWR | GPIO_OUT); - init_timer(&mmc_detect.detect_timer); - mmc_detect.detect_timer.function = mmc_detect_callback; - mmc_detect.detect_timer.data = (unsigned long) &mmc_detect; + corgi_mci_platform_data.detect_delay = msecs_to_jiffies(250); - err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_mmc_detect_int, SA_INTERRUPT, + err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_detect_int, SA_INTERRUPT, "MMC card detect", data); if (err) { printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); @@ -198,7 +181,6 @@ static int corgi_mci_get_ro(struct device *dev) static void corgi_mci_exit(struct device *dev, void *data) { free_irq(CORGI_IRQ_GPIO_nSD_DETECT, data); - del_timer(&mmc_detect.detect_timer); } static struct pxamci_platform_data corgi_mci_platform_data = { -- GitLab From daad56661d56cc382948fc95b74e17d3326b901b Mon Sep 17 00:00:00 2001 From: Richard Purdie <rpurdie@rpsys.net> Date: Fri, 9 Sep 2005 18:54:04 +0100 Subject: [PATCH 054/563] [ARM] 2894/1: Sharp Scoop driver pm_message_t type fix Patch from Richard Purdie Fix a pm_message_t type warning in the Sharp scoop driver Signed-off-by: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- arch/arm/common/scoop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index 688a595598c8a..d3a04c2a2c857 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -91,7 +91,7 @@ EXPORT_SYMBOL(read_scoop_reg); EXPORT_SYMBOL(write_scoop_reg); #ifdef CONFIG_PM -static int scoop_suspend(struct device *dev, uint32_t state, uint32_t level) +static int scoop_suspend(struct device *dev, pm_message_t state, uint32_t level) { if (level == SUSPEND_POWER_DOWN) { struct scoop_dev *sdev = dev_get_drvdata(dev); -- GitLab From 7bcf5c0e7fd9ab4ddb9e24d7e91bda2ac23e5678 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman <gregkh@suse.de> Date: Thu, 18 Aug 2005 14:33:01 +1000 Subject: [PATCH 055/563] [PATCH] PCI: move pci core to use add_hotplug_env_var() This fixes a bug in the environment variables for all PCI device hotplug calls. Thanks to Kay Sievers for pointing out the problem. Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/pci/hotplug.c | 53 +++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index b844bc9723244..10444988a10b5 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -20,46 +20,35 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp, scratch = buffer; - /* stuff we want to pass to /sbin/hotplug */ - envp[i++] = scratch; - length += scnprintf (scratch, buffer_size - length, "PCI_CLASS=%04X", - pdev->class); - if ((buffer_size - length <= 0) || (i >= num_envp)) + + if (add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PCI_CLASS=%04X", pdev->class)) return -ENOMEM; - ++length; - scratch += length; - envp[i++] = scratch; - length += scnprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X", - pdev->vendor, pdev->device); - if ((buffer_size - length <= 0) || (i >= num_envp)) + if (add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) return -ENOMEM; - ++length; - scratch += length; - envp[i++] = scratch; - length += scnprintf (scratch, buffer_size - length, - "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, - pdev->subsystem_device); - if ((buffer_size - length <= 0) || (i >= num_envp)) + if (add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, + pdev->subsystem_device)) return -ENOMEM; - ++length; - scratch += length; - envp[i++] = scratch; - length += scnprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s", - pci_name(pdev)); - if ((buffer_size - length <= 0) || (i >= num_envp)) + if (add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PCI_SLOT_NAME=%s", pci_name(pdev))) return -ENOMEM; - envp[i++] = scratch; - length += scnprintf (scratch, buffer_size - length, - "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", - pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device, - (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), - (u8)(pdev->class)); - if ((buffer_size - length <= 0) || (i >= num_envp)) + if (add_hotplug_env_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device, + (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), + (u8)(pdev->class))) return -ENOMEM; envp[i] = NULL; -- GitLab From 144a50ea5e1487b8b8e722289b4177713354448a Mon Sep 17 00:00:00 2001 From: Dave Jones <davej@redhat.com> Date: Tue, 9 Aug 2005 00:20:10 -0400 Subject: [PATCH 056/563] [PATCH] must_check attributes for PCI layer. Self explanatory really. Some newer gcc's print a warning if a function is used and we don't check its result. We do this for a bunch of things in the kernel already, this extends that to the PCI layer. Based on a patch originally from Arjan van de Ven. Signed-off-by: Dave Jones <davej@redhat.com> Signed-off-by: Arjan van de Ven <arjan@infradead.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- include/linux/pci.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/linux/pci.h b/include/linux/pci.h index 6caaba0af4697..609499356e074 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -376,32 +376,32 @@ static inline int pci_write_config_dword(struct pci_dev *dev, int where, u32 val return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val); } -int pci_enable_device(struct pci_dev *dev); -int pci_enable_device_bars(struct pci_dev *dev, int mask); +int __must_check pci_enable_device(struct pci_dev *dev); +int __must_check pci_enable_device_bars(struct pci_dev *dev, int mask); void pci_disable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); #define HAVE_PCI_SET_MWI -int pci_set_mwi(struct pci_dev *dev); +int __must_check pci_set_mwi(struct pci_dev *dev); void pci_clear_mwi(struct pci_dev *dev); void pci_intx(struct pci_dev *dev, int enable); -int pci_set_dma_mask(struct pci_dev *dev, u64 mask); -int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); +int __must_check pci_set_dma_mask(struct pci_dev *dev, u64 mask); +int __must_check pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); int pci_assign_resource(struct pci_dev *dev, int i); void pci_restore_bars(struct pci_dev *dev); /* ROM control related routines */ -void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size); -void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size); +void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size); +void __iomem __must_check *pci_map_rom_copy(struct pci_dev *pdev, size_t *size); void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom); void pci_remove_rom(struct pci_dev *pdev); /* Power management related routines */ int pci_save_state(struct pci_dev *dev); int pci_restore_state(struct pci_dev *dev); -int pci_set_power_state(struct pci_dev *dev, pci_power_t state); -pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); -int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable); +int __must_check pci_set_power_state(struct pci_dev *dev, pci_power_t state); +pci_power_t __must_check pci_choose_state(struct pci_dev *dev, pm_message_t state); +int __must_check pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable); /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ void pci_bus_assign_resources(struct pci_bus *bus); -- GitLab From cca6e6f5f473ec63e85c87dfc77279ce1ca114e6 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 20:28:49 +0200 Subject: [PATCH 057/563] kbuild: h8300,m68knommu,sh,sh64 use generic asm-offsets.h support h8300, m68knommu, sh and sh64 all used the name asm-offsets.h so minimal changes required. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/h8300/Makefile | 8 -------- arch/m68knommu/Makefile | 10 ---------- arch/sh/Makefile | 11 ++--------- arch/sh64/Makefile | 8 ++------ 4 files changed, 4 insertions(+), 33 deletions(-) diff --git a/arch/h8300/Makefile b/arch/h8300/Makefile index c9b80cffd71d5..40b3f56f3666b 100644 --- a/arch/h8300/Makefile +++ b/arch/h8300/Makefile @@ -61,12 +61,6 @@ archmrproper: archclean: $(Q)$(MAKE) $(clean)=$(boot) -prepare: include/asm-$(ARCH)/asm-offsets.h - -include/asm-$(ARCH)/asm-offsets.h: arch/$(ARCH)/kernel/asm-offsets.s \ - include/asm include/linux/version.h - $(call filechk,gen-asm-offsets) - vmlinux.srec vmlinux.bin: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ @@ -74,5 +68,3 @@ define archhelp echo 'vmlinux.bin - Create raw binary' echo 'vmlinux.srec - Create srec binary' endef - -CLEAN_FILES += include/asm-$(ARCH)/asm-offsets.h diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile index 7ce5e55b2401e..b8fdf191b8f6b 100644 --- a/arch/m68knommu/Makefile +++ b/arch/m68knommu/Makefile @@ -102,21 +102,11 @@ CFLAGS += -DUTS_SYSNAME=\"uClinux\" head-y := arch/m68knommu/platform/$(cpuclass-y)/head.o -CLEAN_FILES := include/asm-$(ARCH)/asm-offsets.h \ - arch/$(ARCH)/kernel/asm-offsets.s - core-y += arch/m68knommu/kernel/ \ arch/m68knommu/mm/ \ $(CLASSDIR) \ arch/m68knommu/platform/$(PLATFORM)/ libs-y += arch/m68knommu/lib/ -prepare: include/asm-$(ARCH)/asm-offsets.h - archclean: $(Q)$(MAKE) $(clean)=arch/m68knommu/boot - -include/asm-$(ARCH)/asm-offsets.h: arch/$(ARCH)/kernel/asm-offsets.s \ - include/asm include/linux/version.h \ - include/config/MARKER - $(call filechk,gen-asm-offsets) diff --git a/arch/sh/Makefile b/arch/sh/Makefile index b5635635b5ee7..19f00d57acf07 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -155,7 +155,7 @@ endif prepare: maketools include/asm-sh/.cpu include/asm-sh/.mach .PHONY: maketools FORCE -maketools: include/asm-sh/asm-offsets.h include/linux/version.h FORCE +maketools: include/linux/version.h FORCE $(Q)$(MAKE) $(build)=arch/sh/tools include/asm-sh/machtypes.h all: zImage @@ -168,14 +168,7 @@ compressed: zImage archclean: $(Q)$(MAKE) $(clean)=$(boot) -CLEAN_FILES += include/asm-sh/machtypes.h include/asm-sh/asm-offsets.h - -arch/sh/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/asm-sh/.cpu include/asm-sh/.mach - -include/asm-sh/asm-offsets.h: arch/sh/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - +CLEAN_FILES += include/asm-sh/machtypes.h define archhelp @echo ' zImage - Compressed kernel image (arch/sh/boot/zImage)' diff --git a/arch/sh64/Makefile b/arch/sh64/Makefile index b4fd8e13fea99..39073734a4761 100644 --- a/arch/sh64/Makefile +++ b/arch/sh64/Makefile @@ -73,11 +73,7 @@ compressed: zImage archclean: $(Q)$(MAKE) $(clean)=$(boot) -prepare: include/asm-$(ARCH)/asm-offsets.h arch/$(ARCH)/lib/syscalltab.h - -include/asm-$(ARCH)/asm-offsets.h: arch/$(ARCH)/kernel/asm-offsets.s \ - include/asm include/linux/version.h - $(call filechk,gen-asm-offsets) +prepare: arch/$(ARCH)/lib/syscalltab.h define filechk_gen-syscalltab (set -e; \ @@ -108,7 +104,7 @@ endef arch/$(ARCH)/lib/syscalltab.h: arch/sh64/kernel/syscalls.S $(call filechk,gen-syscalltab) -CLEAN_FILES += include/asm-$(ARCH)/asm-offsets.h arch/$(ARCH)/lib/syscalltab.h +CLEAN_FILES += arch/$(ARCH)/lib/syscalltab.h define archhelp @echo ' zImage - Compressed kernel image (arch/sh64/boot/zImage)' -- GitLab From 47003497dd819b10874a2291e54df7dc5cf8be57 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 20:35:55 +0200 Subject: [PATCH 058/563] kbuild: arm26,sparc use generic asm-offset support Rename all includes to use asm-offsets.h to match generic name Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/arm26/Makefile | 10 ---------- arch/arm26/kernel/entry.S | 2 +- arch/arm26/lib/copy_page.S | 2 +- arch/arm26/lib/csumpartialcopyuser.S | 2 +- arch/arm26/lib/getuser.S | 2 +- arch/arm26/lib/putuser.S | 2 +- arch/arm26/mm/proc-funcs.S | 2 +- arch/arm26/nwfpe/entry.S | 2 +- arch/sparc/Makefile | 12 +----------- arch/sparc/kernel/entry.S | 2 +- arch/sparc/kernel/sclow.S | 2 +- arch/sparc/mm/hypersparc.S | 2 +- arch/sparc/mm/swift.S | 2 +- arch/sparc/mm/tsunami.S | 2 +- arch/sparc/mm/viking.S | 2 +- include/asm-sparc/ptrace.h | 4 ++-- 16 files changed, 16 insertions(+), 36 deletions(-) diff --git a/arch/arm26/Makefile b/arch/arm26/Makefile index e9cb8ef4f3fbd..844a9e46886e5 100644 --- a/arch/arm26/Makefile +++ b/arch/arm26/Makefile @@ -49,10 +49,6 @@ all: zImage boot := arch/arm26/boot -prepare: include/asm-$(ARCH)/asm_offsets.h -CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h - - .PHONY: maketools FORCE maketools: FORCE @@ -94,12 +90,6 @@ zi:; $(Q)$(MAKE) $(build)=$(boot) zinstall fi; \ ) -arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - define archhelp echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)' echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)' diff --git a/arch/arm26/kernel/entry.S b/arch/arm26/kernel/entry.S index a231dd88d0e13..6d910ea43d34d 100644 --- a/arch/arm26/kernel/entry.S +++ b/arch/arm26/kernel/entry.S @@ -10,7 +10,7 @@ #include <linux/linkage.h> #include <asm/assembler.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/errno.h> #include <asm/hardware.h> #include <asm/sysirq.h> diff --git a/arch/arm26/lib/copy_page.S b/arch/arm26/lib/copy_page.S index 2d79ee12ea1f7..c7511a2739d3f 100644 --- a/arch/arm26/lib/copy_page.S +++ b/arch/arm26/lib/copy_page.S @@ -11,7 +11,7 @@ */ #include <linux/linkage.h> #include <asm/assembler.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> .text .align 5 diff --git a/arch/arm26/lib/csumpartialcopyuser.S b/arch/arm26/lib/csumpartialcopyuser.S index 5b821188e4792..261dd154c1a46 100644 --- a/arch/arm26/lib/csumpartialcopyuser.S +++ b/arch/arm26/lib/csumpartialcopyuser.S @@ -11,7 +11,7 @@ #include <linux/linkage.h> #include <asm/assembler.h> #include <asm/errno.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> .text diff --git a/arch/arm26/lib/getuser.S b/arch/arm26/lib/getuser.S index e6d59b334851c..2b1de7fbfe1fd 100644 --- a/arch/arm26/lib/getuser.S +++ b/arch/arm26/lib/getuser.S @@ -26,7 +26,7 @@ * Note that ADDR_LIMIT is either 0 or 0xc0000000. * Note also that it is intended that __get_user_bad is not global. */ -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/errno.h> diff --git a/arch/arm26/lib/putuser.S b/arch/arm26/lib/putuser.S index 87588cbe46aec..46c7f15f9f2d9 100644 --- a/arch/arm26/lib/putuser.S +++ b/arch/arm26/lib/putuser.S @@ -26,7 +26,7 @@ * Note that ADDR_LIMIT is either 0 or 0xc0000000 * Note also that it is intended that __put_user_bad is not global. */ -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/errno.h> diff --git a/arch/arm26/mm/proc-funcs.S b/arch/arm26/mm/proc-funcs.S index c3d4cd3f457ea..f9fca524c57af 100644 --- a/arch/arm26/mm/proc-funcs.S +++ b/arch/arm26/mm/proc-funcs.S @@ -14,7 +14,7 @@ */ #include <linux/linkage.h> #include <asm/assembler.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/procinfo.h> #include <asm/ptrace.h> diff --git a/arch/arm26/nwfpe/entry.S b/arch/arm26/nwfpe/entry.S index 7d6dfaad80c21..e6312000d9f8e 100644 --- a/arch/arm26/nwfpe/entry.S +++ b/arch/arm26/nwfpe/entry.S @@ -20,7 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> /* This is the kernel's entry point into the floating point emulator. It is called from the kernel with code similar to this: diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 7b3bbaf083a69..dea48f6cff38b 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -59,17 +59,7 @@ image tftpboot.img: vmlinux archclean: $(Q)$(MAKE) $(clean)=$(boot) -prepare: include/asm-$(ARCH)/asm_offsets.h - -arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - -CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h \ - arch/$(ARCH)/kernel/asm-offsets.s \ - arch/$(ARCH)/boot/System.map +CLEAN_FILES += arch/$(ARCH)/boot/System.map # Don't use tabs in echo arguments. define archhelp diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index b448166f5da95..03ecb4e4614e0 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -17,7 +17,7 @@ #include <asm/kgdb.h> #include <asm/contregs.h> #include <asm/ptrace.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/psr.h> #include <asm/vaddrs.h> #include <asm/memreg.h> diff --git a/arch/sparc/kernel/sclow.S b/arch/sparc/kernel/sclow.S index 3a867fc199274..136e37c53d49f 100644 --- a/arch/sparc/kernel/sclow.S +++ b/arch/sparc/kernel/sclow.S @@ -7,7 +7,7 @@ */ #include <asm/ptrace.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/errno.h> #include <asm/winmacro.h> #include <asm/thread_info.h> diff --git a/arch/sparc/mm/hypersparc.S b/arch/sparc/mm/hypersparc.S index 54b8e764b0423..a231cca37216a 100644 --- a/arch/sparc/mm/hypersparc.S +++ b/arch/sparc/mm/hypersparc.S @@ -6,7 +6,7 @@ #include <asm/ptrace.h> #include <asm/psr.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/asi.h> #include <asm/page.h> #include <asm/pgtsrmmu.h> diff --git a/arch/sparc/mm/swift.S b/arch/sparc/mm/swift.S index 2dcaa5ac1a38d..cd90f3fdc4e7a 100644 --- a/arch/sparc/mm/swift.S +++ b/arch/sparc/mm/swift.S @@ -9,7 +9,7 @@ #include <asm/asi.h> #include <asm/page.h> #include <asm/pgtsrmmu.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> .text .align 4 diff --git a/arch/sparc/mm/tsunami.S b/arch/sparc/mm/tsunami.S index 8acd1787fde21..697af617594ae 100644 --- a/arch/sparc/mm/tsunami.S +++ b/arch/sparc/mm/tsunami.S @@ -6,7 +6,7 @@ #include <linux/config.h> #include <asm/ptrace.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/psr.h> #include <asm/asi.h> #include <asm/page.h> diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S index f58712d26bf52..3cbd6de18dde0 100644 --- a/arch/sparc/mm/viking.S +++ b/arch/sparc/mm/viking.S @@ -9,7 +9,7 @@ #include <linux/config.h> #include <asm/ptrace.h> #include <asm/psr.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/asi.h> #include <asm/mxcc.h> #include <asm/page.h> diff --git a/include/asm-sparc/ptrace.h b/include/asm-sparc/ptrace.h index dd9d94d7e0ae4..a8ecb2d6977aa 100644 --- a/include/asm-sparc/ptrace.h +++ b/include/asm-sparc/ptrace.h @@ -73,11 +73,11 @@ extern void show_regs(struct pt_regs *); #endif /* - * The asm_offsets.h is a generated file, so we cannot include it. + * The asm-offsets.h is a generated file, so we cannot include it. * It may be OK for glibc headers, but it's utterly pointless for C code. * The assembly code using those offsets has to include it explicitly. */ -/* #include <asm/asm_offsets.h> */ +/* #include <asm/asm-offsets.h> */ /* These are for pt_regs. */ #define PT_PSR 0x0 -- GitLab From 0013a85454c281faaf064ccb576e373a2881aac8 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 20:57:26 +0200 Subject: [PATCH 059/563] kbuild: m68k,parisc,ppc,ppc64,s390,xtensa use generic asm-offsets.h support Delete obsoleted parts form arch makefiles and rename to asm-offsets.h Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/m68k/Makefile | 9 --------- arch/m68k/fpsp040/skeleton.S | 2 +- arch/m68k/ifpsp060/iskeleton.S | 2 +- arch/m68k/kernel/entry.S | 2 +- arch/m68k/kernel/head.S | 2 +- arch/m68k/math-emu/fp_emu.h | 2 +- arch/parisc/Makefile | 10 +--------- arch/parisc/hpux/gate.S | 2 +- arch/parisc/hpux/wrappers.S | 2 +- arch/parisc/kernel/entry.S | 2 +- arch/parisc/kernel/head.S | 2 +- arch/parisc/kernel/process.c | 2 +- arch/parisc/kernel/ptrace.c | 2 +- arch/parisc/kernel/signal.c | 2 +- arch/parisc/kernel/syscall.S | 2 +- arch/parisc/lib/fixup.S | 2 +- arch/ppc/Makefile | 12 ++---------- arch/ppc/kernel/cpu_setup_6xx.S | 2 +- arch/ppc/kernel/cpu_setup_power4.S | 2 +- arch/ppc/kernel/entry.S | 2 +- arch/ppc/kernel/fpu.S | 2 +- arch/ppc/kernel/head.S | 2 +- arch/ppc/kernel/head_44x.S | 2 +- arch/ppc/kernel/head_4xx.S | 2 +- arch/ppc/kernel/head_8xx.S | 2 +- arch/ppc/kernel/head_fsl_booke.S | 2 +- arch/ppc/kernel/idle_6xx.S | 2 +- arch/ppc/kernel/idle_power4.S | 2 +- arch/ppc/kernel/misc.S | 2 +- arch/ppc/kernel/swsusp.S | 2 +- arch/ppc/mm/hashtable.S | 2 +- arch/ppc/platforms/pmac_sleep.S | 2 +- arch/ppc64/Makefile | 9 --------- arch/ppc64/kernel/cpu_setup_power4.S | 2 +- arch/ppc64/kernel/entry.S | 2 +- arch/ppc64/kernel/head.S | 2 +- arch/ppc64/kernel/idle_power4.S | 2 +- arch/ppc64/kernel/misc.S | 2 +- arch/ppc64/kernel/vdso32/cacheflush.S | 2 +- arch/ppc64/kernel/vdso32/datapage.S | 2 +- arch/ppc64/kernel/vdso32/gettimeofday.S | 2 +- arch/ppc64/kernel/vdso64/cacheflush.S | 2 +- arch/ppc64/kernel/vdso64/datapage.S | 2 +- arch/ppc64/kernel/vdso64/gettimeofday.S | 2 +- arch/ppc64/mm/hash_low.S | 2 +- arch/ppc64/mm/slb_low.S | 2 +- arch/s390/Makefile | 10 ---------- arch/s390/kernel/entry.S | 2 +- arch/s390/kernel/entry64.S | 2 +- arch/s390/kernel/head.S | 2 +- arch/s390/kernel/head64.S | 2 +- arch/s390/lib/uaccess.S | 2 +- arch/s390/lib/uaccess64.S | 2 +- arch/xtensa/Makefile | 10 ++-------- arch/xtensa/kernel/align.S | 2 +- arch/xtensa/kernel/entry.S | 2 +- arch/xtensa/kernel/process.c | 2 +- arch/xtensa/kernel/vectors.S | 2 +- include/asm-ia64/ptrace.h | 2 +- include/asm-ia64/thread_info.h | 2 +- include/asm-parisc/assembly.h | 2 +- include/asm-xtensa/ptrace.h | 2 +- include/asm-xtensa/uaccess.h | 2 +- 63 files changed, 62 insertions(+), 112 deletions(-) diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index 466e7407afc7b..34d826d10f1b6 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -113,14 +113,5 @@ else bzip2 -1c vmlinux >vmlinux.bz2 endif -prepare: include/asm-$(ARCH)/offsets.h -CLEAN_FILES += include/asm-$(ARCH)/offsets.h - -arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - archclean: rm -f vmlinux.gz vmlinux.bz2 diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S index dbc1255a5e994..9571a21d6ad42 100644 --- a/arch/m68k/fpsp040/skeleton.S +++ b/arch/m68k/fpsp040/skeleton.S @@ -40,7 +40,7 @@ #include <linux/linkage.h> #include <asm/entry.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> |SKELETON idnt 2,1 | Motorola 040 Floating Point Software Package diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S index 803a6ecdda81c..4ba2c74da93da 100644 --- a/arch/m68k/ifpsp060/iskeleton.S +++ b/arch/m68k/ifpsp060/iskeleton.S @@ -36,7 +36,7 @@ #include <linux/linkage.h> #include <asm/entry.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> |################################ diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index e964015a31dc9..23ca60a455524 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -42,7 +42,7 @@ #include <asm/traps.h> #include <asm/unistd.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> .globl system_call, buserr, trap .globl resume, ret_from_exception diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S index 7cd6de17c20d4..d4336d846df14 100644 --- a/arch/m68k/kernel/head.S +++ b/arch/m68k/kernel/head.S @@ -263,7 +263,7 @@ #include <asm/entry.h> #include <asm/pgtable.h> #include <asm/page.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #ifdef CONFIG_MAC diff --git a/arch/m68k/math-emu/fp_emu.h b/arch/m68k/math-emu/fp_emu.h index 1d6edc975d89c..c1ecfef7886a6 100644 --- a/arch/m68k/math-emu/fp_emu.h +++ b/arch/m68k/math-emu/fp_emu.h @@ -39,7 +39,7 @@ #define _FP_EMU_H #ifdef __ASSEMBLY__ -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #endif #include <asm/math-emu.h> diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index 0403d2fcb85ef..3b339b1cce137 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -100,15 +100,7 @@ kernel_install: vmlinux install: kernel_install modules_install -prepare: include/asm-parisc/offsets.h - -arch/parisc/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-parisc/offsets.h: arch/parisc/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - -CLEAN_FILES += lifimage include/asm-parisc/offsets.h +CLEAN_FILES += lifimage MRPROPER_FILES += palo.conf define archhelp diff --git a/arch/parisc/hpux/gate.S b/arch/parisc/hpux/gate.S index 2680a1c0fa774..aaaf3306c05ac 100644 --- a/arch/parisc/hpux/gate.S +++ b/arch/parisc/hpux/gate.S @@ -9,7 +9,7 @@ */ #include <asm/assembly.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> #include <asm/errno.h> diff --git a/arch/parisc/hpux/wrappers.S b/arch/parisc/hpux/wrappers.S index 1aa936dfe1476..0b0c3a66b1bec 100644 --- a/arch/parisc/hpux/wrappers.S +++ b/arch/parisc/hpux/wrappers.S @@ -24,7 +24,7 @@ #warning PA64 support needs more work...did first cut #endif -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/assembly.h> #include <asm/signal.h> diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index ee58d37dbb275..be0f07f2fa584 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -23,7 +23,7 @@ */ #include <linux/config.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> /* we have the following possibilities to act on an interruption: * - handle in assembly and use shadowed registers only diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index ddf7e914f15e0..28405edf84488 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -14,7 +14,7 @@ #include <linux/autoconf.h> /* for CONFIG_SMP */ -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/psw.h> #include <asm/pdc.h> diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 4fc04501d5e5d..46b759385115a 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -47,7 +47,7 @@ #include <linux/kallsyms.h> #include <asm/io.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/pdc.h> #include <asm/pdc_chassis.h> #include <asm/pgalloc.h> diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index c07db9dff7cd8..f3428e5e86fb9 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -23,7 +23,7 @@ #include <asm/pgtable.h> #include <asm/system.h> #include <asm/processor.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> /* PSW bits we allow the debugger to modify */ #define USER_PSW_BITS (PSW_N | PSW_V | PSW_CB) diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 55d71c15e1f7c..0224651fd8f15 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -32,7 +32,7 @@ #include <asm/uaccess.h> #include <asm/pgalloc.h> #include <asm/cacheflush.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #ifdef CONFIG_COMPAT #include <linux/compat.h> diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 32ea701f4d201..8c7a7185cd3b0 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -7,7 +7,7 @@ * sorry about the wall, puffin.. */ -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> #include <asm/errno.h> #include <asm/psw.h> diff --git a/arch/parisc/lib/fixup.S b/arch/parisc/lib/fixup.S index 134f0cd240f55..1b91612ed964e 100644 --- a/arch/parisc/lib/fixup.S +++ b/arch/parisc/lib/fixup.S @@ -20,7 +20,7 @@ * Fixup routines for kernel exception handling. */ #include <linux/config.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/assembly.h> #include <asm/errno.h> diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index d1b6e6dcb5041..4b3fe395ffa4d 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -105,13 +105,7 @@ archclean: $(Q)$(MAKE) $(clean)=arch/ppc/boot $(Q)rm -rf include3 -prepare: include/asm-$(ARCH)/offsets.h checkbin - -arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) +prepare: checkbin # Temporary hack until we have migrated to asm-powerpc include/asm: include3/asm @@ -143,7 +137,5 @@ checkbin: false ; \ fi -CLEAN_FILES += include/asm-$(ARCH)/offsets.h \ - arch/$(ARCH)/kernel/asm-offsets.s \ - $(TOUT) +CLEAN_FILES += $(TOUT) diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S index bd037caa40559..1f37b7eafac21 100644 --- a/arch/ppc/kernel/cpu_setup_6xx.S +++ b/arch/ppc/kernel/cpu_setup_6xx.S @@ -15,7 +15,7 @@ #include <asm/ppc_asm.h> #include <asm/cputable.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cache.h> _GLOBAL(__setup_cpu_601) diff --git a/arch/ppc/kernel/cpu_setup_power4.S b/arch/ppc/kernel/cpu_setup_power4.S index f2ea1a990f170..304589aebdbcc 100644 --- a/arch/ppc/kernel/cpu_setup_power4.S +++ b/arch/ppc/kernel/cpu_setup_power4.S @@ -15,7 +15,7 @@ #include <asm/ppc_asm.h> #include <asm/cputable.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cache.h> _GLOBAL(__970_cpu_preinit) diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index cb83045e2edfb..03d4886869f3e 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -29,7 +29,7 @@ #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> #undef SHOW_SYSCALLS diff --git a/arch/ppc/kernel/fpu.S b/arch/ppc/kernel/fpu.S index 6189b26f640f2..665d7d34304cd 100644 --- a/arch/ppc/kernel/fpu.S +++ b/arch/ppc/kernel/fpu.S @@ -18,7 +18,7 @@ #include <asm/cache.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> /* * This task wants to use the FPU now. diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index a931d773715fa..55daf1210f322 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -31,7 +31,7 @@ #include <asm/cache.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #ifdef CONFIG_APUS #include <asm/amigappc.h> diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S index 9e68e32edb606..599245b0407ed 100644 --- a/arch/ppc/kernel/head_44x.S +++ b/arch/ppc/kernel/head_44x.S @@ -40,7 +40,7 @@ #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include "head_booke.h" diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S index ca9518b96c6eb..8562b807b37c2 100644 --- a/arch/ppc/kernel/head_4xx.S +++ b/arch/ppc/kernel/head_4xx.S @@ -40,7 +40,7 @@ #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> /* As with the other PowerPC ports, it is expected that when code * execution begins here, the following registers contain valid, yet diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S index eb18cadb3755b..cb1a3a54a0264 100644 --- a/arch/ppc/kernel/head_8xx.S +++ b/arch/ppc/kernel/head_8xx.S @@ -30,7 +30,7 @@ #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> /* Macro to make the code more readable. */ #ifdef CONFIG_8xx_CPU6 diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S index 4028f4c7d9789..8e52e84083161 100644 --- a/arch/ppc/kernel/head_fsl_booke.S +++ b/arch/ppc/kernel/head_fsl_booke.S @@ -41,7 +41,7 @@ #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include "head_booke.h" /* As with the other PowerPC ports, it is expected that when code diff --git a/arch/ppc/kernel/idle_6xx.S b/arch/ppc/kernel/idle_6xx.S index 25d009c75f7bc..1a2194cf68281 100644 --- a/arch/ppc/kernel/idle_6xx.S +++ b/arch/ppc/kernel/idle_6xx.S @@ -20,7 +20,7 @@ #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #undef DEBUG diff --git a/arch/ppc/kernel/idle_power4.S b/arch/ppc/kernel/idle_power4.S index 73a58ff03900a..cc0d535365cdb 100644 --- a/arch/ppc/kernel/idle_power4.S +++ b/arch/ppc/kernel/idle_power4.S @@ -20,7 +20,7 @@ #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #undef DEBUG diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index ce71b4a015859..90d917d2e856f 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -23,7 +23,7 @@ #include <asm/mmu.h> #include <asm/ppc_asm.h> #include <asm/thread_info.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> .text diff --git a/arch/ppc/kernel/swsusp.S b/arch/ppc/kernel/swsusp.S index 55148bb88d399..69773cc1a85f3 100644 --- a/arch/ppc/kernel/swsusp.S +++ b/arch/ppc/kernel/swsusp.S @@ -5,7 +5,7 @@ #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> /* diff --git a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S index ab83132a7ed0b..3ec87c91343e8 100644 --- a/arch/ppc/mm/hashtable.S +++ b/arch/ppc/mm/hashtable.S @@ -30,7 +30,7 @@ #include <asm/cputable.h> #include <asm/ppc_asm.h> #include <asm/thread_info.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #ifdef CONFIG_SMP .comm mmu_hash_lock,4 diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S index 016a74649155b..8d67adc769258 100644 --- a/arch/ppc/platforms/pmac_sleep.S +++ b/arch/ppc/platforms/pmac_sleep.S @@ -17,7 +17,7 @@ #include <asm/cputable.h> #include <asm/cache.h> #include <asm/thread_info.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #define MAGIC 0x4c617273 /* 'Lars' */ diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 8189953a372c9..d795775a5cd79 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -116,13 +116,6 @@ archclean: $(Q)$(MAKE) $(clean)=$(boot) $(Q)rm -rf include3 -prepare: include/asm-ppc64/offsets.h - -arch/ppc64/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-ppc64/offsets.h: arch/ppc64/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) # Temporary hack until we have migrated to asm-powerpc include/asm: include3/asm @@ -136,5 +129,3 @@ define archhelp echo ' sourced from arch/$(ARCH)/boot/ramdisk.image.gz' echo ' (arch/$(ARCH)/boot/zImage.initrd)' endef - -CLEAN_FILES += include/asm-ppc64/offsets.h diff --git a/arch/ppc64/kernel/cpu_setup_power4.S b/arch/ppc64/kernel/cpu_setup_power4.S index 0482c063c26ee..bfce609e8e6be 100644 --- a/arch/ppc64/kernel/cpu_setup_power4.S +++ b/arch/ppc64/kernel/cpu_setup_power4.S @@ -15,7 +15,7 @@ #include <asm/ppc_asm.h> #include <asm/cputable.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cache.h> _GLOBAL(__970_cpu_preinit) diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S index bf99b4a92f208..d133a49cdf897 100644 --- a/arch/ppc64/kernel/entry.S +++ b/arch/ppc64/kernel/entry.S @@ -28,7 +28,7 @@ #include <asm/mmu.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cputable.h> #ifdef CONFIG_PPC_ISERIES diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index b436206e317df..58c314738c998 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -30,7 +30,7 @@ #include <asm/mmu.h> #include <asm/systemcfg.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/bug.h> #include <asm/cputable.h> #include <asm/setup.h> diff --git a/arch/ppc64/kernel/idle_power4.S b/arch/ppc64/kernel/idle_power4.S index 97e4a26550402..ca02afe2a7953 100644 --- a/arch/ppc64/kernel/idle_power4.S +++ b/arch/ppc64/kernel/idle_power4.S @@ -20,7 +20,7 @@ #include <asm/cputable.h> #include <asm/thread_info.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #undef DEBUG diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index 6d860c1d9fa08..757903544e245 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -26,7 +26,7 @@ #include <asm/page.h> #include <asm/cache.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cputable.h> .text diff --git a/arch/ppc64/kernel/vdso32/cacheflush.S b/arch/ppc64/kernel/vdso32/cacheflush.S index 0ed7ea721715b..c8db993574ee8 100644 --- a/arch/ppc64/kernel/vdso32/cacheflush.S +++ b/arch/ppc64/kernel/vdso32/cacheflush.S @@ -13,7 +13,7 @@ #include <asm/processor.h> #include <asm/ppc_asm.h> #include <asm/vdso.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> .text diff --git a/arch/ppc64/kernel/vdso32/datapage.S b/arch/ppc64/kernel/vdso32/datapage.S index 29b6bd32e1f1a..4f4eb0be3992e 100644 --- a/arch/ppc64/kernel/vdso32/datapage.S +++ b/arch/ppc64/kernel/vdso32/datapage.S @@ -12,7 +12,7 @@ #include <linux/config.h> #include <asm/processor.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> #include <asm/vdso.h> diff --git a/arch/ppc64/kernel/vdso32/gettimeofday.S b/arch/ppc64/kernel/vdso32/gettimeofday.S index 2b48bf1fb109f..07f1c1c650c89 100644 --- a/arch/ppc64/kernel/vdso32/gettimeofday.S +++ b/arch/ppc64/kernel/vdso32/gettimeofday.S @@ -13,7 +13,7 @@ #include <asm/processor.h> #include <asm/ppc_asm.h> #include <asm/vdso.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> .text diff --git a/arch/ppc64/kernel/vdso64/cacheflush.S b/arch/ppc64/kernel/vdso64/cacheflush.S index e0725b7b70034..d4a0ad28d534e 100644 --- a/arch/ppc64/kernel/vdso64/cacheflush.S +++ b/arch/ppc64/kernel/vdso64/cacheflush.S @@ -13,7 +13,7 @@ #include <asm/processor.h> #include <asm/ppc_asm.h> #include <asm/vdso.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> .text diff --git a/arch/ppc64/kernel/vdso64/datapage.S b/arch/ppc64/kernel/vdso64/datapage.S index 18afd971c9d97..ed6e599ae8242 100644 --- a/arch/ppc64/kernel/vdso64/datapage.S +++ b/arch/ppc64/kernel/vdso64/datapage.S @@ -12,7 +12,7 @@ #include <linux/config.h> #include <asm/processor.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> #include <asm/vdso.h> diff --git a/arch/ppc64/kernel/vdso64/gettimeofday.S b/arch/ppc64/kernel/vdso64/gettimeofday.S index ed3f970ff05ed..f6df8028570a7 100644 --- a/arch/ppc64/kernel/vdso64/gettimeofday.S +++ b/arch/ppc64/kernel/vdso64/gettimeofday.S @@ -14,7 +14,7 @@ #include <asm/processor.h> #include <asm/ppc_asm.h> #include <asm/vdso.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> .text /* diff --git a/arch/ppc64/mm/hash_low.S b/arch/ppc64/mm/hash_low.S index 35eb49e1b8908..ee5a5d36bfa8e 100644 --- a/arch/ppc64/mm/hash_low.S +++ b/arch/ppc64/mm/hash_low.S @@ -16,7 +16,7 @@ #include <asm/page.h> #include <asm/types.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cputable.h> .text diff --git a/arch/ppc64/mm/slb_low.S b/arch/ppc64/mm/slb_low.S index 698d6b9ed6d19..a3a03da503bcb 100644 --- a/arch/ppc64/mm/slb_low.S +++ b/arch/ppc64/mm/slb_low.S @@ -21,7 +21,7 @@ #include <asm/page.h> #include <asm/mmu.h> #include <asm/ppc_asm.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/cputable.h> /* void slb_allocate(unsigned long ea); diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 3cd8dd25c9d73..189c8f3a369ce 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -100,16 +100,6 @@ image: vmlinux archclean: $(Q)$(MAKE) $(clean)=$(boot) -prepare: include/asm-$(ARCH)/offsets.h - -arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - -CLEAN_FILES += include/asm-$(ARCH)/offsets.h - # Don't use tabs in echo arguments define archhelp echo '* image - Kernel image for IPL ($(boot)/image)' diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index cbe7d6a2d02cd..58fc7fbcb40e1 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -18,7 +18,7 @@ #include <asm/errno.h> #include <asm/ptrace.h> #include <asm/thread_info.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> #include <asm/page.h> diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index fb77b72ab2627..d0c9ffaa25db7 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -18,7 +18,7 @@ #include <asm/errno.h> #include <asm/ptrace.h> #include <asm/thread_info.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/unistd.h> #include <asm/page.h> diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 2710e66fefbaf..55654b6e16dce 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -30,7 +30,7 @@ #include <linux/config.h> #include <asm/setup.h> #include <asm/lowcore.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/page.h> diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 9a8263a153cba..c9ff0404c875e 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -30,7 +30,7 @@ #include <linux/config.h> #include <asm/setup.h> #include <asm/lowcore.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/page.h> diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S index e8029ef42ef2d..88fc94fe64880 100644 --- a/arch/s390/lib/uaccess.S +++ b/arch/s390/lib/uaccess.S @@ -11,7 +11,7 @@ #include <linux/errno.h> #include <asm/lowcore.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> .text .align 4 diff --git a/arch/s390/lib/uaccess64.S b/arch/s390/lib/uaccess64.S index 0ca56972f4f09..50219786fc7ac 100644 --- a/arch/s390/lib/uaccess64.S +++ b/arch/s390/lib/uaccess64.S @@ -11,7 +11,7 @@ #include <linux/errno.h> #include <asm/lowcore.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> .text .align 4 diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile index 27847e4ffcbfa..67ef4cd173b9b 100644 --- a/arch/xtensa/Makefile +++ b/arch/xtensa/Makefile @@ -66,13 +66,7 @@ boot := arch/xtensa/boot archinc := include/asm-xtensa -arch/xtensa/kernel/asm-offsets.s: \ - arch/xtensa/kernel/asm-offsets.c $(archinc)/.platform - -include/asm-xtensa/offsets.h: arch/xtensa/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - -prepare: $(archinc)/.platform $(archinc)/offsets.h +prepare: $(archinc)/.platform # Update machine cpu and platform symlinks if something which affects # them changed. @@ -94,7 +88,7 @@ bzImage : zImage zImage zImage.initrd: vmlinux $(Q)$(MAKE) $(build)=$(boot) $@ -CLEAN_FILES += arch/xtensa/vmlinux.lds $(archinc)/offset.h \ +CLEAN_FILES += arch/xtensa/vmlinux.lds \ $(archinc)/platform $(archinc)/xtensa/config \ $(archinc)/.platform diff --git a/arch/xtensa/kernel/align.S b/arch/xtensa/kernel/align.S index 74b1e90ef08c2..a4956578a24df 100644 --- a/arch/xtensa/kernel/align.S +++ b/arch/xtensa/kernel/align.S @@ -19,7 +19,7 @@ #include <asm/ptrace.h> #include <asm/ptrace.h> #include <asm/current.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/page.h> diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index c64a01f71de69..5c018c503dfa0 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -14,7 +14,7 @@ */ #include <linux/linkage.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/processor.h> #include <asm/thread_info.h> #include <asm/uaccess.h> diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 4099703b14bed..c83bb0d41787b 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -43,7 +43,7 @@ #include <asm/mmu.h> #include <asm/irq.h> #include <asm/atomic.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/coprocessor.h> extern void ret_from_fork(void); diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S index 81808f0c67420..0e74397bfa2bd 100644 --- a/arch/xtensa/kernel/vectors.S +++ b/arch/xtensa/kernel/vectors.S @@ -46,7 +46,7 @@ #include <asm/ptrace.h> #include <asm/ptrace.h> #include <asm/current.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/page.h> diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h index 0bef19538406f..c8766def9ee6f 100644 --- a/include/asm-ia64/ptrace.h +++ b/include/asm-ia64/ptrace.h @@ -57,7 +57,7 @@ #include <linux/config.h> #include <asm/fpu.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> /* * Base-2 logarithm of number of pages to allocate per task structure diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h index 7dc8951708a38..b2c79f0694f8b 100644 --- a/include/asm-ia64/thread_info.h +++ b/include/asm-ia64/thread_info.h @@ -5,7 +5,7 @@ #ifndef _ASM_IA64_THREAD_INFO_H #define _ASM_IA64_THREAD_INFO_H -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/processor.h> #include <asm/ptrace.h> diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h index cbc286f49b365..30b023411fefd 100644 --- a/include/asm-parisc/assembly.h +++ b/include/asm-parisc/assembly.h @@ -63,7 +63,7 @@ .level 2.0w #endif -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/page.h> #include <asm/asmregs.h> diff --git a/include/asm-xtensa/ptrace.h b/include/asm-xtensa/ptrace.h index 2848a5ff8349b..aa4fd7fb3ce71 100644 --- a/include/asm-xtensa/ptrace.h +++ b/include/asm-xtensa/ptrace.h @@ -127,7 +127,7 @@ extern void show_regs(struct pt_regs *); #else /* __ASSEMBLY__ */ #ifdef __KERNEL__ -# include <asm/offsets.h> +# include <asm/asm-offsets.h> #define PT_REGS_OFFSET (KERNEL_STACK_SIZE - PT_USER_SIZE) #endif diff --git a/include/asm-xtensa/uaccess.h b/include/asm-xtensa/uaccess.h index fc268ac923c0b..06a22b83ba178 100644 --- a/include/asm-xtensa/uaccess.h +++ b/include/asm-xtensa/uaccess.h @@ -25,7 +25,7 @@ #define _ASMLANGUAGE #include <asm/current.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/processor.h> /* -- GitLab From e6ae744dd2eae8e00af328b11b1fe77cb0931136 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 21:08:59 +0200 Subject: [PATCH 060/563] kbuild: arm - use generic asm-offsets.h support Delete obsoleted stuff from arch Makefile and rename constants.h to asm-offsets.h Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/arm/Makefile | 9 ++------- arch/arm/kernel/entry-header.S | 2 +- arch/arm/kernel/head.S | 2 +- arch/arm/kernel/iwmmxt.S | 2 +- arch/arm/lib/copy_page.S | 2 +- arch/arm/lib/csumpartialcopyuser.S | 2 +- arch/arm/lib/getuser.S | 2 +- arch/arm/lib/putuser.S | 2 +- arch/arm/mm/copypage-v3.S | 2 +- arch/arm/mm/copypage-v4wb.S | 2 +- arch/arm/mm/copypage-v4wt.S | 2 +- arch/arm/mm/proc-arm1020.S | 2 +- arch/arm/mm/proc-arm1020e.S | 2 +- arch/arm/mm/proc-arm1022.S | 2 +- arch/arm/mm/proc-arm1026.S | 2 +- arch/arm/mm/proc-arm6_7.S | 2 +- arch/arm/mm/proc-arm720.S | 2 +- arch/arm/mm/proc-macros.S | 2 +- arch/arm/mm/proc-sa110.S | 2 +- arch/arm/mm/proc-sa1100.S | 2 +- arch/arm/mm/proc-v6.S | 2 +- arch/arm/mm/tlb-v3.S | 2 +- arch/arm/mm/tlb-v4.S | 2 +- arch/arm/mm/tlb-v4wb.S | 2 +- arch/arm/mm/tlb-v4wbi.S | 2 +- arch/arm/mm/tlb-v6.S | 2 +- arch/arm/nwfpe/entry26.S | 2 +- arch/arm/vfp/entry.S | 2 +- 28 files changed, 29 insertions(+), 34 deletions(-) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 67f1453ade05e..e625ac66f49b2 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -178,7 +178,7 @@ endif prepare: maketools include/asm-arm/.arch .PHONY: maketools FORCE -maketools: include/asm-arm/constants.h include/linux/version.h FORCE +maketools: include/linux/version.h FORCE $(Q)$(MAKE) $(build)=arch/arm/tools include/asm-arm/mach-types.h # Convert bzImage to zImage @@ -190,7 +190,7 @@ zImage Image xipImage bootpImage uImage: vmlinux zinstall install: vmlinux $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ -CLEAN_FILES += include/asm-arm/constants.h* include/asm-arm/mach-types.h \ +CLEAN_FILES += include/asm-arm/mach-types.h \ include/asm-arm/arch include/asm-arm/.arch # We use MRPROPER_FILES and CLEAN_FILES now @@ -201,11 +201,6 @@ archclean: bp:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/bootpImage i zi:; $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ -arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/asm-arm/.arch - -include/asm-$(ARCH)/constants.h: arch/$(ARCH)/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) define archhelp echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)' diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index afef21273963a..648cfff93138b 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -3,7 +3,7 @@ #include <linux/linkage.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/errno.h> #include <asm/thread_info.h> diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 1155cf07c8710..5396263513486 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -20,7 +20,7 @@ #include <asm/mach-types.h> #include <asm/procinfo.h> #include <asm/ptrace.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/system.h> diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S index 8f74e24536ba7..24c7b0477a096 100644 --- a/arch/arm/kernel/iwmmxt.S +++ b/arch/arm/kernel/iwmmxt.S @@ -17,7 +17,7 @@ #include <linux/linkage.h> #include <asm/ptrace.h> #include <asm/thread_info.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #define MMX_WR0 (0x00) #define MMX_WR1 (0x08) diff --git a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S index 4c38abdbe497b..68117968482bb 100644 --- a/arch/arm/lib/copy_page.S +++ b/arch/arm/lib/copy_page.S @@ -11,7 +11,7 @@ */ #include <linux/linkage.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #define COPY_COUNT (PAGE_SZ/64 PLD( -1 )) diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S index 46a2dc962e9dd..333bca292de93 100644 --- a/arch/arm/lib/csumpartialcopyuser.S +++ b/arch/arm/lib/csumpartialcopyuser.S @@ -13,7 +13,7 @@ #include <linux/linkage.h> #include <asm/assembler.h> #include <asm/errno.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> .text diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index 64aa6f4fe5e4a..d204018070a49 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -26,7 +26,7 @@ * Note that ADDR_LIMIT is either 0 or 0xc0000000. * Note also that it is intended that __get_user_bad is not global. */ -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/errno.h> diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S index b09398d95aac7..4593e9c07f053 100644 --- a/arch/arm/lib/putuser.S +++ b/arch/arm/lib/putuser.S @@ -26,7 +26,7 @@ * Note that ADDR_LIMIT is either 0 or 0xc0000000 * Note also that it is intended that __put_user_bad is not global. */ -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/errno.h> diff --git a/arch/arm/mm/copypage-v3.S b/arch/arm/mm/copypage-v3.S index 4940f1908316a..3c58ebbf0359c 100644 --- a/arch/arm/mm/copypage-v3.S +++ b/arch/arm/mm/copypage-v3.S @@ -12,7 +12,7 @@ #include <linux/linkage.h> #include <linux/init.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> .text .align 5 diff --git a/arch/arm/mm/copypage-v4wb.S b/arch/arm/mm/copypage-v4wb.S index b94c345ceb940..83117354b1cde 100644 --- a/arch/arm/mm/copypage-v4wb.S +++ b/arch/arm/mm/copypage-v4wb.S @@ -11,7 +11,7 @@ */ #include <linux/linkage.h> #include <linux/init.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> .text .align 5 diff --git a/arch/arm/mm/copypage-v4wt.S b/arch/arm/mm/copypage-v4wt.S index 976793937a937..e1f2af28d549e 100644 --- a/arch/arm/mm/copypage-v4wt.S +++ b/arch/arm/mm/copypage-v4wt.S @@ -14,7 +14,7 @@ */ #include <linux/linkage.h> #include <linux/init.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> .text .align 5 diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S index 5c0ae5260d1ca..1d739d282a453 100644 --- a/arch/arm/mm/proc-arm1020.S +++ b/arch/arm/mm/proc-arm1020.S @@ -28,7 +28,7 @@ #include <linux/config.h> #include <linux/init.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/procinfo.h> #include <asm/ptrace.h> diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S index d69389c4d4ba5..9b725665b5c77 100644 --- a/arch/arm/mm/proc-arm1020e.S +++ b/arch/arm/mm/proc-arm1020e.S @@ -28,7 +28,7 @@ #include <linux/config.h> #include <linux/init.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/procinfo.h> #include <asm/ptrace.h> diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S index 747ed963e1dfd..37b70fa21c767 100644 --- a/arch/arm/mm/proc-arm1022.S +++ b/arch/arm/mm/proc-arm1022.S @@ -17,7 +17,7 @@ #include <linux/config.h> #include <linux/init.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/procinfo.h> #include <asm/ptrace.h> diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S index 248110c9cf139..931b690d1be24 100644 --- a/arch/arm/mm/proc-arm1026.S +++ b/arch/arm/mm/proc-arm1026.S @@ -17,7 +17,7 @@ #include <linux/config.h> #include <linux/init.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/procinfo.h> #include <asm/ptrace.h> diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S index 189ef6a71ba10..d0f1bbb48f6c2 100644 --- a/arch/arm/mm/proc-arm6_7.S +++ b/arch/arm/mm/proc-arm6_7.S @@ -13,7 +13,7 @@ #include <linux/linkage.h> #include <linux/init.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/procinfo.h> #include <asm/ptrace.h> diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S index 57cfa6a2f54fd..c69c9de323917 100644 --- a/arch/arm/mm/proc-arm720.S +++ b/arch/arm/mm/proc-arm720.S @@ -33,7 +33,7 @@ #include <linux/linkage.h> #include <linux/init.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/procinfo.h> #include <asm/ptrace.h> diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index 9137fe563599a..7cfc2604a1ee9 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -4,7 +4,7 @@ * VMA_VM_FLAGS * VM_EXEC */ -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> /* diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S index 360cae905692b..34f7e7d3f419c 100644 --- a/arch/arm/mm/proc-sa110.S +++ b/arch/arm/mm/proc-sa110.S @@ -15,7 +15,7 @@ #include <linux/linkage.h> #include <linux/init.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/procinfo.h> #include <asm/hardware.h> #include <asm/pgtable.h> diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S index d447cd5f3dd9b..ca14f80d5ab4b 100644 --- a/arch/arm/mm/proc-sa1100.S +++ b/arch/arm/mm/proc-sa1100.S @@ -20,7 +20,7 @@ #include <linux/linkage.h> #include <linux/init.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/procinfo.h> #include <asm/hardware.h> #include <asm/pgtable.h> diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 139a38670c5d0..eb34823c9dbf6 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -11,7 +11,7 @@ */ #include <linux/linkage.h> #include <asm/assembler.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/procinfo.h> #include <asm/pgtable.h> diff --git a/arch/arm/mm/tlb-v3.S b/arch/arm/mm/tlb-v3.S index 44b0daeaff9bd..c10786ec8e0a4 100644 --- a/arch/arm/mm/tlb-v3.S +++ b/arch/arm/mm/tlb-v3.S @@ -13,7 +13,7 @@ */ #include <linux/linkage.h> #include <linux/init.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/tlbflush.h> #include "proc-macros.S" diff --git a/arch/arm/mm/tlb-v4.S b/arch/arm/mm/tlb-v4.S index db82ee4682485..d6c94457c2b9d 100644 --- a/arch/arm/mm/tlb-v4.S +++ b/arch/arm/mm/tlb-v4.S @@ -14,7 +14,7 @@ */ #include <linux/linkage.h> #include <linux/init.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/tlbflush.h> #include "proc-macros.S" diff --git a/arch/arm/mm/tlb-v4wb.S b/arch/arm/mm/tlb-v4wb.S index 7908d5f1f1304..cb829ca7845d0 100644 --- a/arch/arm/mm/tlb-v4wb.S +++ b/arch/arm/mm/tlb-v4wb.S @@ -14,7 +14,7 @@ */ #include <linux/linkage.h> #include <linux/init.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/tlbflush.h> #include "proc-macros.S" diff --git a/arch/arm/mm/tlb-v4wbi.S b/arch/arm/mm/tlb-v4wbi.S index efbe94bbe1a74..60cfc4a25dd5b 100644 --- a/arch/arm/mm/tlb-v4wbi.S +++ b/arch/arm/mm/tlb-v4wbi.S @@ -14,7 +14,7 @@ */ #include <linux/linkage.h> #include <linux/init.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/tlbflush.h> #include "proc-macros.S" diff --git a/arch/arm/mm/tlb-v6.S b/arch/arm/mm/tlb-v6.S index 99ed26e78adfe..6f76b89ef46ea 100644 --- a/arch/arm/mm/tlb-v6.S +++ b/arch/arm/mm/tlb-v6.S @@ -11,7 +11,7 @@ * These assume a split I/D TLB. */ #include <linux/linkage.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/page.h> #include <asm/tlbflush.h> #include "proc-macros.S" diff --git a/arch/arm/nwfpe/entry26.S b/arch/arm/nwfpe/entry26.S index 0ed38b0913dbb..51940a96d6a6b 100644 --- a/arch/arm/nwfpe/entry26.S +++ b/arch/arm/nwfpe/entry26.S @@ -20,7 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <asm/constants.h> +#include <asm/asm-offsets.h> /* This is the kernel's entry point into the floating point emulator. It is called from the kernel with code similar to this: diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index e73c8deca592c..6f17187ab32aa 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -17,7 +17,7 @@ */ #include <linux/linkage.h> #include <linux/init.h> -#include <asm/constants.h> +#include <asm/asm-offsets.h> #include <asm/vfpmacros.h> .globl do_vfp -- GitLab From e2d5df935d8a82cb7a2c50726628fa928aa89b9b Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 21:28:48 +0200 Subject: [PATCH 061/563] kbuild: alpha,x86_64 use generic asm-offsets.h support Delete obsolete stuff from arch makefiles Rename .h file to asm-offsets.h Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/alpha/Makefile | 11 ----------- arch/alpha/kernel/entry.S | 2 +- arch/alpha/kernel/head.S | 2 +- arch/alpha/lib/dbg_stackcheck.S | 2 +- arch/alpha/lib/dbg_stackkill.S | 2 +- arch/x86_64/Makefile | 10 ---------- arch/x86_64/ia32/ia32entry.S | 2 +- arch/x86_64/ia32/vsyscall-syscall.S | 2 +- arch/x86_64/ia32/vsyscall-sysenter.S | 2 +- arch/x86_64/kernel/entry.S | 2 +- arch/x86_64/kernel/suspend_asm.S | 2 +- arch/x86_64/lib/copy_user.S | 2 +- arch/x86_64/lib/getuser.S | 2 +- arch/x86_64/lib/putuser.S | 2 +- include/asm-x86_64/current.h | 2 +- 15 files changed, 13 insertions(+), 34 deletions(-) diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile index 22ebfb2be0e4c..1b704ee54bf3a 100644 --- a/arch/alpha/Makefile +++ b/arch/alpha/Makefile @@ -108,20 +108,9 @@ $(boot)/vmlinux.gz: vmlinux bootimage bootpfile bootpzfile: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ - -prepare: include/asm-$(ARCH)/asm_offsets.h - -arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - archclean: $(Q)$(MAKE) $(clean)=$(boot) -CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h - define archhelp echo '* boot - Compressed kernel image (arch/alpha/boot/vmlinux.gz)' echo ' bootimage - SRM bootable image (arch/alpha/boot/bootimage)' diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index f0927ee53f29c..76cc0cb5fc2e4 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -5,7 +5,7 @@ */ #include <linux/config.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/pal.h> #include <asm/errno.h> diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S index 4ca2e404708a4..0905721fcbcab 100644 --- a/arch/alpha/kernel/head.S +++ b/arch/alpha/kernel/head.S @@ -9,7 +9,7 @@ #include <linux/config.h> #include <asm/system.h> -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> .globl swapper_pg_dir .globl _stext diff --git a/arch/alpha/lib/dbg_stackcheck.S b/arch/alpha/lib/dbg_stackcheck.S index cc5ce3a5fcad2..3c1f3e6522e5d 100644 --- a/arch/alpha/lib/dbg_stackcheck.S +++ b/arch/alpha/lib/dbg_stackcheck.S @@ -5,7 +5,7 @@ * Verify that we have not overflowed the stack. Oops if we have. */ -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> .text .set noat diff --git a/arch/alpha/lib/dbg_stackkill.S b/arch/alpha/lib/dbg_stackkill.S index e09f2ae1e09e3..e9f6a9dcf2b7c 100644 --- a/arch/alpha/lib/dbg_stackkill.S +++ b/arch/alpha/lib/dbg_stackkill.S @@ -6,7 +6,7 @@ * uninitialized local variables in the act. */ -#include <asm/asm_offsets.h> +#include <asm/asm-offsets.h> .text .set noat diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 4c6ed96d5f7c5..a9cd42e61828d 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -86,16 +86,6 @@ install fdimage fdimage144 fdimage288: vmlinux archclean: $(Q)$(MAKE) $(clean)=$(boot) -prepare: include/asm-$(ARCH)/offset.h - -arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/offset.h: arch/$(ARCH)/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - -CLEAN_FILES += include/asm-$(ARCH)/offset.h - define archhelp echo '* bzImage - Compressed kernel image (arch/$(ARCH)/boot/bzImage)' echo ' install - Install kernel using' diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index f174083d55672..5244f803203d6 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -6,7 +6,7 @@ #include <asm/dwarf2.h> #include <asm/calling.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/current.h> #include <asm/errno.h> #include <asm/ia32_unistd.h> diff --git a/arch/x86_64/ia32/vsyscall-syscall.S b/arch/x86_64/ia32/vsyscall-syscall.S index e2aaf3de8a428..b024965bb689f 100644 --- a/arch/x86_64/ia32/vsyscall-syscall.S +++ b/arch/x86_64/ia32/vsyscall-syscall.S @@ -3,7 +3,7 @@ */ #include <asm/ia32_unistd.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/segment.h> .text diff --git a/arch/x86_64/ia32/vsyscall-sysenter.S b/arch/x86_64/ia32/vsyscall-sysenter.S index 8fb8e0ff3afa7..71f3de586b566 100644 --- a/arch/x86_64/ia32/vsyscall-sysenter.S +++ b/arch/x86_64/ia32/vsyscall-sysenter.S @@ -3,7 +3,7 @@ */ #include <asm/ia32_unistd.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> .text .section .text.vsyscall,"ax" diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index be51dbe1f75ec..3620508c8bd9b 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -36,7 +36,7 @@ #include <asm/errno.h> #include <asm/dwarf2.h> #include <asm/calling.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/msr.h> #include <asm/unistd.h> #include <asm/thread_info.h> diff --git a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm.S index 53f8e1659511f..4d659e97df100 100644 --- a/arch/x86_64/kernel/suspend_asm.S +++ b/arch/x86_64/kernel/suspend_asm.S @@ -14,7 +14,7 @@ #include <linux/linkage.h> #include <asm/segment.h> #include <asm/page.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> ENTRY(swsusp_arch_suspend) diff --git a/arch/x86_64/lib/copy_user.S b/arch/x86_64/lib/copy_user.S index bd556c8042488..dfa358b05c893 100644 --- a/arch/x86_64/lib/copy_user.S +++ b/arch/x86_64/lib/copy_user.S @@ -7,7 +7,7 @@ #define FIX_ALIGNMENT 1 #include <asm/current.h> - #include <asm/offset.h> + #include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/cpufeature.h> diff --git a/arch/x86_64/lib/getuser.S b/arch/x86_64/lib/getuser.S index f80bafee8669f..3844d5e885a4d 100644 --- a/arch/x86_64/lib/getuser.S +++ b/arch/x86_64/lib/getuser.S @@ -29,7 +29,7 @@ #include <linux/linkage.h> #include <asm/page.h> #include <asm/errno.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> .text diff --git a/arch/x86_64/lib/putuser.S b/arch/x86_64/lib/putuser.S index 5828b8191667d..7f5593974e2d0 100644 --- a/arch/x86_64/lib/putuser.S +++ b/arch/x86_64/lib/putuser.S @@ -27,7 +27,7 @@ #include <linux/linkage.h> #include <asm/page.h> #include <asm/errno.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/thread_info.h> .text diff --git a/include/asm-x86_64/current.h b/include/asm-x86_64/current.h index 7db560ee6f703..bc8adecee66d7 100644 --- a/include/asm-x86_64/current.h +++ b/include/asm-x86_64/current.h @@ -17,7 +17,7 @@ static inline struct task_struct *get_current(void) #else #ifndef ASM_OFFSET_H -#include <asm/offset.h> +#include <asm/asm-offsets.h> #endif #define GET_CURRENT(reg) movq %gs:(pda_pcurrent),reg -- GitLab From fb61a8615fce15f30b1bb1cf265ed05e251b9ed8 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 21:39:46 +0200 Subject: [PATCH 062/563] kbuild: v850 use generic asm-offsets.h support Deleted obsolete stuff from arch makefile Renamed .c file to asm-offsets.h Fix include of asm-offsets.h to use new name Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/v850/Makefile | 14 +------------- arch/v850/kernel/{asm-consts.c => asm-offsets.c} | 0 arch/v850/kernel/entry.S | 2 +- 3 files changed, 2 insertions(+), 14 deletions(-) rename arch/v850/kernel/{asm-consts.c => asm-offsets.c} (100%) diff --git a/arch/v850/Makefile b/arch/v850/Makefile index bf38ca0ad7811..8be9aacb20a72 100644 --- a/arch/v850/Makefile +++ b/arch/v850/Makefile @@ -51,16 +51,4 @@ root_fs_image_force: $(ROOT_FS_IMAGE) $(OBJCOPY) $(OBJCOPY_FLAGS_BLOB) --rename-section .data=.root,alloc,load,readonly,data,contents $< root_fs_image.o endif - -prepare: include/asm-$(ARCH)/asm-consts.h - -# Generate constants from C code for use by asm files -arch/$(ARCH)/kernel/asm-consts.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/asm-consts.h: arch/$(ARCH)/kernel/asm-consts.s - $(call filechk,gen-asm-offsets) - -CLEAN_FILES += include/asm-$(ARCH)/asm-consts.h \ - arch/$(ARCH)/kernel/asm-consts.s \ - root_fs_image.o +CLEAN_FILES += root_fs_image.o diff --git a/arch/v850/kernel/asm-consts.c b/arch/v850/kernel/asm-offsets.c similarity index 100% rename from arch/v850/kernel/asm-consts.c rename to arch/v850/kernel/asm-offsets.c diff --git a/arch/v850/kernel/entry.S b/arch/v850/kernel/entry.S index 895e27b1d839f..d991e4547dbb6 100644 --- a/arch/v850/kernel/entry.S +++ b/arch/v850/kernel/entry.S @@ -22,7 +22,7 @@ #include <asm/irq.h> #include <asm/errno.h> -#include <asm/asm-consts.h> +#include <asm/asm-offsets.h> /* Make a slightly more convenient alias for C_SYMBOL_NAME. */ -- GitLab From 39e01cb874cbf694bd0b0c44f54c4f270e2aa556 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 22:03:13 +0200 Subject: [PATCH 063/563] kbuild: ia64 use generic asm-offsets.h support Delete obsolete stuff from arch Makefile Rename file to asm-offsets.h The trick used in the arch Makefile to circumvent the circular dependency is kept. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/ia64/Makefile | 21 +++++++-------------- arch/ia64/ia32/ia32_entry.S | 2 +- arch/ia64/kernel/entry.S | 2 +- arch/ia64/kernel/fsys.S | 2 +- arch/ia64/kernel/gate.S | 2 +- arch/ia64/kernel/head.S | 2 +- arch/ia64/kernel/ivt.S | 2 +- 7 files changed, 13 insertions(+), 20 deletions(-) diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index f9bd88ada708b..7ed678cf5e416 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -82,25 +82,18 @@ unwcheck: vmlinux archclean: $(Q)$(MAKE) $(clean)=$(boot) -CLEAN_FILES += include/asm-ia64/.offsets.h.stamp vmlinux.gz bootloader - -MRPROPER_FILES += include/asm-ia64/offsets.h - -prepare: include/asm-ia64/offsets.h - -arch/ia64/kernel/asm-offsets.s: include/asm include/linux/version.h include/config/MARKER - -include/asm-ia64/offsets.h: arch/ia64/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) - -arch/ia64/kernel/asm-offsets.s: include/asm-ia64/.offsets.h.stamp +prepare: include/asm-ia64/.offsets.h.stamp include/asm-ia64/.offsets.h.stamp: mkdir -p include/asm-ia64 - [ -s include/asm-ia64/offsets.h ] \ - || echo "#define IA64_TASK_SIZE 0" > include/asm-ia64/offsets.h + [ -s include/asm-ia64/asm-offsets.h ] \ + || echo "#define IA64_TASK_SIZE 0" > include/asm-ia64/asm-offsets.h touch $@ + + +CLEAN_FILES += vmlinux.gz bootloader include/asm-ia64/.offsets.h.stamp + boot: lib/lib.a vmlinux $(Q)$(MAKE) $(build)=$(boot) $@ diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index 0708edb06cc4d..494fad6bf376d 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -1,6 +1,6 @@ #include <asm/asmmacro.h> #include <asm/ia32.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/signal.h> #include <asm/thread_info.h> diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 9be53e1ea4043..6d70fec82d0e8 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -37,7 +37,7 @@ #include <asm/cache.h> #include <asm/errno.h> #include <asm/kregs.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/percpu.h> #include <asm/processor.h> diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S index 7d7684a369d38..2ddbac6f49993 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S @@ -14,7 +14,7 @@ #include <asm/asmmacro.h> #include <asm/errno.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/percpu.h> #include <asm/thread_info.h> #include <asm/sal.h> diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S index 86948ce63e43a..86064ca98952f 100644 --- a/arch/ia64/kernel/gate.S +++ b/arch/ia64/kernel/gate.S @@ -10,7 +10,7 @@ #include <asm/asmmacro.h> #include <asm/errno.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/sigcontext.h> #include <asm/system.h> #include <asm/unistd.h> diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index 8d3a9291b47f8..bfe65b2e86214 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -25,7 +25,7 @@ #include <asm/fpu.h> #include <asm/kregs.h> #include <asm/mmu_context.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/pal.h> #include <asm/pgtable.h> #include <asm/processor.h> diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index 3bb3a13c40475..3ba8384cb43de 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -44,7 +44,7 @@ #include <asm/break.h> #include <asm/ia32.h> #include <asm/kregs.h> -#include <asm/offsets.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/ptrace.h> -- GitLab From 048eb582f3f89737d4a29668de9935e6feea7c36 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 22:32:31 +0200 Subject: [PATCH 064/563] kbuild: mips use generic asm-offsets.h support Removed obsolete stuff from arch makefile. mips had a special rule for generating asm-offsets.h so preserved it using an architecture specific hook in top-level Kbuild file. Renamed .h file to asm-offsets.h Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- Kbuild | 9 ++++++++- arch/mips/Makefile | 35 ++------------------------------- arch/mips/kernel/r2300_fpu.S | 2 +- arch/mips/kernel/r2300_switch.S | 2 +- arch/mips/kernel/r4k_fpu.S | 2 +- arch/mips/kernel/r4k_switch.S | 2 +- arch/mips/kernel/r6000_fpu.S | 2 +- arch/mips/kernel/scall32-o32.S | 2 +- arch/mips/kernel/scall64-64.S | 2 +- arch/mips/kernel/syscall.c | 2 +- arch/mips/lib-32/memset.S | 2 +- arch/mips/lib-64/memset.S | 2 +- arch/mips/lib/memcpy.S | 2 +- arch/mips/lib/strlen_user.S | 2 +- arch/mips/lib/strncpy_user.S | 2 +- arch/mips/lib/strnlen_user.S | 2 +- include/asm-mips/asmmacro-32.h | 2 +- include/asm-mips/asmmacro-64.h | 2 +- include/asm-mips/sim.h | 2 +- include/asm-mips/stackframe.h | 2 +- 20 files changed, 28 insertions(+), 52 deletions(-) diff --git a/Kbuild b/Kbuild index 197ece85034ba..1880e6f760aab 100644 --- a/Kbuild +++ b/Kbuild @@ -13,6 +13,13 @@ always := $(offsets-file) targets := $(offsets-file) targets += arch/$(ARCH)/kernel/asm-offsets.s +# Default sed regexp - multiline due to syntax constraints +define sed-y + "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}" +endef +# Override default regexp for specific architectures +sed-$(CONFIG_MIPS) := "/^@@@/s///p" + quiet_cmd_offsets = GEN $@ define cmd_offsets cat $< | \ @@ -26,7 +33,7 @@ define cmd_offsets echo " *"; \ echo " */"; \ echo ""; \ - sed -ne "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"; \ + sed -ne $(sed-y); \ echo ""; \ echo "#endif" ) > $@ endef diff --git a/arch/mips/Makefile b/arch/mips/Makefile index b0fdaee8d8d95..346e803f153bc 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -720,38 +720,7 @@ archclean: @$(MAKE) $(clean)=arch/mips/boot @$(MAKE) $(clean)=arch/mips/lasat -# Generate <asm/offset.h -# -# The default rule is suffering from funny problems on MIPS so we using our -# own ... -# -# --------------------------------------------------------------------------- - -define filechk_gen-asm-offset.h - (set -e; \ - echo "#ifndef _ASM_OFFSET_H"; \ - echo "#define _ASM_OFFSET_H"; \ - echo "/*"; \ - echo " * DO NOT MODIFY."; \ - echo " *"; \ - echo " * This file was generated by arch/$(ARCH)/Makefile"; \ - echo " *"; \ - echo " */"; \ - echo ""; \ - sed -ne "/^@@@/s///p"; \ - echo "#endif /* _ASM_OFFSET_H */" ) -endef - -prepare: include/asm-$(ARCH)/offset.h - -arch/$(ARCH)/kernel/offset.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/offset.h: arch/$(ARCH)/kernel/offset.s - $(call filechk,gen-asm-offset.h) - -CLEAN_FILES += include/asm-$(ARCH)/offset.h.tmp \ - include/asm-$(ARCH)/offset.h \ - vmlinux.32 \ + +CLEAN_FILES += vmlinux.32 \ vmlinux.64 \ vmlinux.ecoff diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S index f83c31f720c4d..ac68e68339db6 100644 --- a/arch/mips/kernel/r2300_fpu.S +++ b/arch/mips/kernel/r2300_fpu.S @@ -15,7 +15,7 @@ #include <asm/errno.h> #include <asm/fpregdef.h> #include <asm/mipsregs.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> #define EX(a,b) \ diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S index f10019640ee99..0d9c4a32a9c2d 100644 --- a/arch/mips/kernel/r2300_switch.S +++ b/arch/mips/kernel/r2300_switch.S @@ -15,7 +15,7 @@ #include <asm/cachectl.h> #include <asm/fpregdef.h> #include <asm/mipsregs.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/page.h> #include <asm/regdef.h> #include <asm/stackframe.h> diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index aba665bcb3864..1a14c6b188299 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -17,7 +17,7 @@ #include <asm/errno.h> #include <asm/fpregdef.h> #include <asm/mipsregs.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> .macro EX insn, reg, src diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index e02b7722ccb8d..d2afbd19a9c8a 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -15,7 +15,7 @@ #include <asm/cachectl.h> #include <asm/fpregdef.h> #include <asm/mipsregs.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/page.h> #include <asm/pgtable-bits.h> #include <asm/regdef.h> diff --git a/arch/mips/kernel/r6000_fpu.S b/arch/mips/kernel/r6000_fpu.S index d8d3b13fe57ff..43cda53f5af68 100644 --- a/arch/mips/kernel/r6000_fpu.S +++ b/arch/mips/kernel/r6000_fpu.S @@ -13,7 +13,7 @@ #include <asm/asm.h> #include <asm/fpregdef.h> #include <asm/mipsregs.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> .set noreorder diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 344f2e29eb616..17b5030fb6ea2 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -19,7 +19,7 @@ #include <asm/thread_info.h> #include <asm/unistd.h> #include <asm/war.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> /* Highest syscall used of any syscall flavour */ #define MAX_SYSCALL_NO __NR_O32_Linux + __NR_O32_Linux_syscalls diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 32efb888160ab..ffb22a2068bf9 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -14,7 +14,7 @@ #include <asm/mipsregs.h> #include <asm/regdef.h> #include <asm/stackframe.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/sysmips.h> #include <asm/thread_info.h> #include <asm/unistd.h> diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index ae2a1312d4efe..21e3e13a4b446 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -31,7 +31,7 @@ #include <asm/cachectl.h> #include <asm/cacheflush.h> #include <asm/ipc.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/signal.h> #include <asm/sim.h> #include <asm/shmparam.h> diff --git a/arch/mips/lib-32/memset.S b/arch/mips/lib-32/memset.S index ad9ff4071ce92..1981485bd48b7 100644 --- a/arch/mips/lib-32/memset.S +++ b/arch/mips/lib-32/memset.S @@ -7,7 +7,7 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #include <asm/asm.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> #define EX(insn,reg,addr,handler) \ diff --git a/arch/mips/lib-64/memset.S b/arch/mips/lib-64/memset.S index 242f1976cfaf0..e2c42c85113b3 100644 --- a/arch/mips/lib-64/memset.S +++ b/arch/mips/lib-64/memset.S @@ -7,7 +7,7 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #include <asm/asm.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> #define EX(insn,reg,addr,handler) \ diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S index 90ee8d43261f5..a78865f765478 100644 --- a/arch/mips/lib/memcpy.S +++ b/arch/mips/lib/memcpy.S @@ -14,7 +14,7 @@ */ #include <linux/config.h> #include <asm/asm.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> #define dst a0 diff --git a/arch/mips/lib/strlen_user.S b/arch/mips/lib/strlen_user.S index 07660e86c99da..eca558d83a373 100644 --- a/arch/mips/lib/strlen_user.S +++ b/arch/mips/lib/strlen_user.S @@ -7,7 +7,7 @@ * Copyright (c) 1999 Silicon Graphics, Inc. */ #include <asm/asm.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> #define EX(insn,reg,addr,handler) \ diff --git a/arch/mips/lib/strncpy_user.S b/arch/mips/lib/strncpy_user.S index 14bed17c1648a..d16c76fbfac72 100644 --- a/arch/mips/lib/strncpy_user.S +++ b/arch/mips/lib/strncpy_user.S @@ -7,7 +7,7 @@ */ #include <linux/errno.h> #include <asm/asm.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> #define EX(insn,reg,addr,handler) \ diff --git a/arch/mips/lib/strnlen_user.S b/arch/mips/lib/strnlen_user.S index 6e7a8eed4de8f..c0ea15194a0e8 100644 --- a/arch/mips/lib/strnlen_user.S +++ b/arch/mips/lib/strnlen_user.S @@ -7,7 +7,7 @@ * Copyright (c) 1999 Silicon Graphics, Inc. */ #include <asm/asm.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> #define EX(insn,reg,addr,handler) \ diff --git a/include/asm-mips/asmmacro-32.h b/include/asm-mips/asmmacro-32.h index ac8823df25546..11daf5ceb7b4e 100644 --- a/include/asm-mips/asmmacro-32.h +++ b/include/asm-mips/asmmacro-32.h @@ -7,7 +7,7 @@ #ifndef _ASM_ASMMACRO_32_H #define _ASM_ASMMACRO_32_H -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> #include <asm/fpregdef.h> #include <asm/mipsregs.h> diff --git a/include/asm-mips/asmmacro-64.h b/include/asm-mips/asmmacro-64.h index bbed35511f5a7..559c355b9b868 100644 --- a/include/asm-mips/asmmacro-64.h +++ b/include/asm-mips/asmmacro-64.h @@ -8,7 +8,7 @@ #ifndef _ASM_ASMMACRO_64_H #define _ASM_ASMMACRO_64_H -#include <asm/offset.h> +#include <asm/asm-offsets.h> #include <asm/regdef.h> #include <asm/fpregdef.h> #include <asm/mipsregs.h> diff --git a/include/asm-mips/sim.h b/include/asm-mips/sim.h index 3ccfe09fa744c..9c2af1b00e197 100644 --- a/include/asm-mips/sim.h +++ b/include/asm-mips/sim.h @@ -11,7 +11,7 @@ #include <linux/config.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> #define __str2(x) #x #define __str(x) __str2(x) diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h index fb42f99f85278..7b5e64600bc89 100644 --- a/include/asm-mips/stackframe.h +++ b/include/asm-mips/stackframe.h @@ -15,7 +15,7 @@ #include <asm/asm.h> #include <asm/mipsregs.h> -#include <asm/offset.h> +#include <asm/asm-offsets.h> .macro SAVE_AT .set push -- GitLab From cb7b593c2c808b32a1ea188599713c434b95f849 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger <shemminger@osdl.org> Date: Fri, 9 Sep 2005 13:35:42 -0700 Subject: [PATCH 065/563] [IPV4] fib_trie: fix proc interface Create one iterator for walking over FIB trie, and use it for all the /proc functions. Add a /proc/net/route output for backwards compatibility with old applications. Make initialization of fib_trie same as fib_hash so no #ifdef is needed in af_inet.c Fixes: http://bugzilla.kernel.org/show_bug.cgi?id=5209 Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv4/af_inet.c | 13 - net/ipv4/fib_trie.c | 804 +++++++++++++++++++++----------------------- 2 files changed, 385 insertions(+), 432 deletions(-) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index bf147f8db3994..a9d84f93442c9 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1248,11 +1248,6 @@ module_init(inet_init); /* ------------------------------------------------------------------------ */ #ifdef CONFIG_PROC_FS -#ifdef CONFIG_IP_FIB_TRIE -extern int fib_stat_proc_init(void); -extern void fib_stat_proc_exit(void); -#endif - static int __init ipv4_proc_init(void) { int rc = 0; @@ -1265,19 +1260,11 @@ static int __init ipv4_proc_init(void) goto out_udp; if (fib_proc_init()) goto out_fib; -#ifdef CONFIG_IP_FIB_TRIE - if (fib_stat_proc_init()) - goto out_fib_stat; -#endif if (ip_misc_proc_init()) goto out_misc; out: return rc; out_misc: -#ifdef CONFIG_IP_FIB_TRIE - fib_stat_proc_exit(); -out_fib_stat: -#endif fib_proc_exit(); out_fib: udp4_proc_exit(); diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index b2dea4e5da77c..1b63b48241643 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -43,7 +43,7 @@ * 2 of the License, or (at your option) any later version. */ -#define VERSION "0.402" +#define VERSION "0.403" #include <linux/config.h> #include <asm/uaccess.h> @@ -164,7 +164,6 @@ static struct node *resize(struct trie *t, struct tnode *tn); static struct tnode *inflate(struct trie *t, struct tnode *tn); static struct tnode *halve(struct trie *t, struct tnode *tn); static void tnode_free(struct tnode *tn); -static void trie_dump_seq(struct seq_file *seq, struct trie *t); static kmem_cache_t *fn_alias_kmem __read_mostly; static struct trie *trie_local = NULL, *trie_main = NULL; @@ -1971,558 +1970,525 @@ struct fib_table * __init fib_hash_init(int id) return tb; } -/* Trie dump functions */ +#ifdef CONFIG_PROC_FS +/* Depth first Trie walk iterator */ +struct fib_trie_iter { + struct tnode *tnode; + struct trie *trie; + unsigned index; + unsigned depth; +}; -static void putspace_seq(struct seq_file *seq, int n) +static struct node *fib_trie_get_next(struct fib_trie_iter *iter) { - while (n--) - seq_printf(seq, " "); -} + struct tnode *tn = iter->tnode; + unsigned cindex = iter->index; + struct tnode *p; -static void printbin_seq(struct seq_file *seq, unsigned int v, int bits) -{ - while (bits--) - seq_printf(seq, "%s", (v & (1<<bits))?"1":"0"); -} + pr_debug("get_next iter={node=%p index=%d depth=%d}\n", + iter->tnode, iter->index, iter->depth); +rescan: + while (cindex < (1<<tn->bits)) { + struct node *n = tnode_get_child(tn, cindex); -static void printnode_seq(struct seq_file *seq, int indent, struct node *n, - int pend, int cindex, int bits) -{ - putspace_seq(seq, indent); - if (IS_LEAF(n)) - seq_printf(seq, "|"); - else - seq_printf(seq, "+"); - if (bits) { - seq_printf(seq, "%d/", cindex); - printbin_seq(seq, cindex, bits); - seq_printf(seq, ": "); - } else - seq_printf(seq, "<root>: "); - seq_printf(seq, "%s:%p ", IS_LEAF(n)?"Leaf":"Internal node", n); + if (n) { + if (IS_LEAF(n)) { + iter->tnode = tn; + iter->index = cindex + 1; + } else { + /* push down one level */ + iter->tnode = (struct tnode *) n; + iter->index = 0; + ++iter->depth; + } + return n; + } - if (IS_LEAF(n)) { - struct leaf *l = (struct leaf *)n; - struct fib_alias *fa; - int i; + ++cindex; + } - seq_printf(seq, "key=%d.%d.%d.%d\n", - n->key >> 24, (n->key >> 16) % 256, (n->key >> 8) % 256, n->key % 256); - - for (i = 32; i >= 0; i--) - if (find_leaf_info(&l->list, i)) { - struct list_head *fa_head = get_fa_head(l, i); - - if (!fa_head) - continue; - - if (list_empty(fa_head)) - continue; - - putspace_seq(seq, indent+2); - seq_printf(seq, "{/%d...dumping}\n", i); - - list_for_each_entry_rcu(fa, fa_head, fa_list) { - putspace_seq(seq, indent+2); - if (fa->fa_info == NULL) { - seq_printf(seq, "Error fa_info=NULL\n"); - continue; - } - if (fa->fa_info->fib_nh == NULL) { - seq_printf(seq, "Error _fib_nh=NULL\n"); - continue; - } - - seq_printf(seq, "{type=%d scope=%d TOS=%d}\n", - fa->fa_type, - fa->fa_scope, - fa->fa_tos); - } - } - } else { - struct tnode *tn = (struct tnode *)n; - int plen = ((struct tnode *)n)->pos; - t_key prf = MASK_PFX(n->key, plen); - - seq_printf(seq, "key=%d.%d.%d.%d/%d\n", - prf >> 24, (prf >> 16) % 256, (prf >> 8) % 256, prf % 256, plen); - - putspace_seq(seq, indent); seq_printf(seq, "| "); - seq_printf(seq, "{key prefix=%08x/", tn->key & TKEY_GET_MASK(0, tn->pos)); - printbin_seq(seq, tkey_extract_bits(tn->key, 0, tn->pos), tn->pos); - seq_printf(seq, "}\n"); - putspace_seq(seq, indent); seq_printf(seq, "| "); - seq_printf(seq, "{pos=%d", tn->pos); - seq_printf(seq, " (skip=%d bits)", tn->pos - pend); - seq_printf(seq, " bits=%d (%u children)}\n", tn->bits, (1 << tn->bits)); - putspace_seq(seq, indent); seq_printf(seq, "| "); - seq_printf(seq, "{empty=%d full=%d}\n", tn->empty_children, tn->full_children); + /* Current node exhausted, pop back up */ + p = NODE_PARENT(tn); + if (p) { + cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1; + tn = p; + --iter->depth; + goto rescan; } + + /* got root? */ + return NULL; } -static void trie_dump_seq(struct seq_file *seq, struct trie *t) +static struct node *fib_trie_get_first(struct fib_trie_iter *iter, + struct trie *t) { - struct node *n; - int cindex = 0; - int indent = 1; - int pend = 0; - int depth = 0; - struct tnode *tn; - - rcu_read_lock(); - n = rcu_dereference(t->trie); - seq_printf(seq, "------ trie_dump of t=%p ------\n", t); + struct node *n = rcu_dereference(t->trie); - if (!n) { - seq_printf(seq, "------ trie is empty\n"); - - rcu_read_unlock(); - return; + if (n && IS_TNODE(n)) { + iter->tnode = (struct tnode *) n; + iter->trie = t; + iter->index = 0; + iter->depth = 0; + return n; } + return NULL; +} - printnode_seq(seq, indent, n, pend, cindex, 0); - - if (!IS_TNODE(n)) { - rcu_read_unlock(); - return; - } - - tn = (struct tnode *)n; - pend = tn->pos+tn->bits; - putspace_seq(seq, indent); seq_printf(seq, "\\--\n"); - indent += 3; - depth++; - - while (tn && cindex < (1 << tn->bits)) { - struct node *child = rcu_dereference(tn->child[cindex]); - if (!child) - cindex++; - else { - /* Got a child */ - printnode_seq(seq, indent, child, pend, - cindex, tn->bits); - - if (IS_LEAF(child)) - cindex++; - - else { - /* - * New tnode. Decend one level - */ - - depth++; - n = child; - tn = (struct tnode *)n; - pend = tn->pos+tn->bits; - putspace_seq(seq, indent); - seq_printf(seq, "\\--\n"); - indent += 3; - cindex = 0; - } - } - - /* - * Test if we are done - */ - - while (cindex >= (1 << tn->bits)) { - /* - * Move upwards and test for root - * pop off all traversed nodes - */ +static void trie_collect_stats(struct trie *t, struct trie_stat *s) +{ + struct node *n; + struct fib_trie_iter iter; - if (NODE_PARENT(tn) == NULL) { - tn = NULL; - break; - } + memset(s, 0, sizeof(*s)); - cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits); - cindex++; - tn = NODE_PARENT(tn); - pend = tn->pos + tn->bits; - indent -= 3; - depth--; + rcu_read_lock(); + for (n = fib_trie_get_first(&iter, t); n; + n = fib_trie_get_next(&iter)) { + if (IS_LEAF(n)) { + s->leaves++; + s->totdepth += iter.depth; + if (iter.depth > s->maxdepth) + s->maxdepth = iter.depth; + } else { + const struct tnode *tn = (const struct tnode *) n; + int i; + + s->tnodes++; + s->nodesizes[tn->bits]++; + for (i = 0; i < (1<<tn->bits); i++) + if (!tn->child[i]) + s->nullpointers++; } } rcu_read_unlock(); } -static struct trie_stat *trie_stat_new(void) +/* + * This outputs /proc/net/fib_triestats + */ +static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat) { - struct trie_stat *s; - int i; + unsigned i, max, pointers, bytes, avdepth; - s = kmalloc(sizeof(struct trie_stat), GFP_KERNEL); - if (!s) - return NULL; + if (stat->leaves) + avdepth = stat->totdepth*100 / stat->leaves; + else + avdepth = 0; - s->totdepth = 0; - s->maxdepth = 0; - s->tnodes = 0; - s->leaves = 0; - s->nullpointers = 0; + seq_printf(seq, "\tAver depth: %d.%02d\n", avdepth / 100, avdepth % 100 ); + seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth); - for (i = 0; i < MAX_CHILDS; i++) - s->nodesizes[i] = 0; + seq_printf(seq, "\tLeaves: %u\n", stat->leaves); - return s; -} + bytes = sizeof(struct leaf) * stat->leaves; + seq_printf(seq, "\tInternal nodes: %d\n\t", stat->tnodes); + bytes += sizeof(struct tnode) * stat->tnodes; -static struct trie_stat *trie_collect_stats(struct trie *t) -{ - struct node *n; - struct trie_stat *s = trie_stat_new(); - int cindex = 0; - int pend = 0; - int depth = 0; + max = MAX_CHILDS-1; + while (max >= 0 && stat->nodesizes[max] == 0) + max--; - if (!s) - return NULL; + pointers = 0; + for (i = 1; i <= max; i++) + if (stat->nodesizes[i] != 0) { + seq_printf(seq, " %d: %d", i, stat->nodesizes[i]); + pointers += (1<<i) * stat->nodesizes[i]; + } + seq_putc(seq, '\n'); + seq_printf(seq, "\tPointers: %d\n", pointers); - rcu_read_lock(); - n = rcu_dereference(t->trie); + bytes += sizeof(struct node *) * pointers; + seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers); + seq_printf(seq, "Total size: %d kB\n", (bytes + 1023) / 1024); - if (!n) - return s; +#ifdef CONFIG_IP_FIB_TRIE_STATS + seq_printf(seq, "Counters:\n---------\n"); + seq_printf(seq,"gets = %d\n", t->stats.gets); + seq_printf(seq,"backtracks = %d\n", t->stats.backtrack); + seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed); + seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss); + seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit); + seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped); +#ifdef CLEAR_STATS + memset(&(t->stats), 0, sizeof(t->stats)); +#endif +#endif /* CONFIG_IP_FIB_TRIE_STATS */ +} - if (IS_TNODE(n)) { - struct tnode *tn = (struct tnode *)n; - pend = tn->pos+tn->bits; - s->nodesizes[tn->bits]++; - depth++; - - while (tn && cindex < (1 << tn->bits)) { - struct node *ch = rcu_dereference(tn->child[cindex]); - if (ch) { - - /* Got a child */ - - if (IS_LEAF(tn->child[cindex])) { - cindex++; - - /* stats */ - if (depth > s->maxdepth) - s->maxdepth = depth; - s->totdepth += depth; - s->leaves++; - } else { - /* - * New tnode. Decend one level - */ - - s->tnodes++; - s->nodesizes[tn->bits]++; - depth++; - - n = ch; - tn = (struct tnode *)n; - pend = tn->pos+tn->bits; - - cindex = 0; - } - } else { - cindex++; - s->nullpointers++; - } +static int fib_triestat_seq_show(struct seq_file *seq, void *v) +{ + struct trie_stat *stat; - /* - * Test if we are done - */ + stat = kmalloc(sizeof(*stat), GFP_KERNEL); + if (!stat) + return -ENOMEM; - while (cindex >= (1 << tn->bits)) { - /* - * Move upwards and test for root - * pop off all traversed nodes - */ + seq_printf(seq, "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n", + sizeof(struct leaf), sizeof(struct tnode)); - if (NODE_PARENT(tn) == NULL) { - tn = NULL; - n = NULL; - break; - } + if (trie_local) { + seq_printf(seq, "Local:\n"); + trie_collect_stats(trie_local, stat); + trie_show_stats(seq, stat); + } - cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits); - tn = NODE_PARENT(tn); - cindex++; - n = (struct node *)tn; - pend = tn->pos+tn->bits; - depth--; - } - } + if (trie_main) { + seq_printf(seq, "Main:\n"); + trie_collect_stats(trie_main, stat); + trie_show_stats(seq, stat); } + kfree(stat); - rcu_read_unlock(); - return s; + return 0; } -#ifdef CONFIG_PROC_FS - -static struct fib_alias *fib_triestat_get_first(struct seq_file *seq) +static int fib_triestat_seq_open(struct inode *inode, struct file *file) { - return NULL; + return single_open(file, fib_triestat_seq_show, NULL); } -static struct fib_alias *fib_triestat_get_next(struct seq_file *seq) +static struct file_operations fib_triestat_fops = { + .owner = THIS_MODULE, + .open = fib_triestat_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, + loff_t pos) { + loff_t idx = 0; + struct node *n; + + for (n = fib_trie_get_first(iter, trie_local); + n; ++idx, n = fib_trie_get_next(iter)) { + if (pos == idx) + return n; + } + + for (n = fib_trie_get_first(iter, trie_main); + n; ++idx, n = fib_trie_get_next(iter)) { + if (pos == idx) + return n; + } return NULL; } -static void *fib_triestat_seq_start(struct seq_file *seq, loff_t *pos) +static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) { - if (!ip_fib_main_table) - return NULL; - - if (*pos) - return fib_triestat_get_next(seq); - else + rcu_read_lock(); + if (*pos == 0) return SEQ_START_TOKEN; + return fib_trie_get_idx(seq->private, *pos - 1); } -static void *fib_triestat_seq_next(struct seq_file *seq, void *v, loff_t *pos) +static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) { + struct fib_trie_iter *iter = seq->private; + void *l = v; + ++*pos; if (v == SEQ_START_TOKEN) - return fib_triestat_get_first(seq); - else - return fib_triestat_get_next(seq); -} + return fib_trie_get_idx(iter, 0); -static void fib_triestat_seq_stop(struct seq_file *seq, void *v) -{ + v = fib_trie_get_next(iter); + BUG_ON(v == l); + if (v) + return v; -} + /* continue scan in next trie */ + if (iter->trie == trie_local) + return fib_trie_get_first(iter, trie_main); -/* - * This outputs /proc/net/fib_triestats - * - * It always works in backward compatibility mode. - * The format of the file is not supposed to be changed. - */ + return NULL; +} -static void collect_and_show(struct trie *t, struct seq_file *seq) +static void fib_trie_seq_stop(struct seq_file *seq, void *v) { - int bytes = 0; /* How many bytes are used, a ref is 4 bytes */ - int i, max, pointers; - struct trie_stat *stat; - int avdepth; - - stat = trie_collect_stats(t); - - bytes = 0; - seq_printf(seq, "trie=%p\n", t); - - if (stat) { - if (stat->leaves) - avdepth = stat->totdepth*100 / stat->leaves; - else - avdepth = 0; - seq_printf(seq, "Aver depth: %d.%02d\n", avdepth / 100, avdepth % 100); - seq_printf(seq, "Max depth: %4d\n", stat->maxdepth); + rcu_read_unlock(); +} - seq_printf(seq, "Leaves: %d\n", stat->leaves); - bytes += sizeof(struct leaf) * stat->leaves; - seq_printf(seq, "Internal nodes: %d\n", stat->tnodes); - bytes += sizeof(struct tnode) * stat->tnodes; +static void seq_indent(struct seq_file *seq, int n) +{ + while (n-- > 0) seq_puts(seq, " "); +} - max = MAX_CHILDS-1; +static inline const char *rtn_scope(enum rt_scope_t s) +{ + static char buf[32]; - while (max >= 0 && stat->nodesizes[max] == 0) - max--; - pointers = 0; + switch(s) { + case RT_SCOPE_UNIVERSE: return "universe"; + case RT_SCOPE_SITE: return "site"; + case RT_SCOPE_LINK: return "link"; + case RT_SCOPE_HOST: return "host"; + case RT_SCOPE_NOWHERE: return "nowhere"; + default: + snprintf(buf, sizeof(buf), "scope=%d", s); + return buf; + } +} - for (i = 1; i <= max; i++) - if (stat->nodesizes[i] != 0) { - seq_printf(seq, " %d: %d", i, stat->nodesizes[i]); - pointers += (1<<i) * stat->nodesizes[i]; - } - seq_printf(seq, "\n"); - seq_printf(seq, "Pointers: %d\n", pointers); - bytes += sizeof(struct node *) * pointers; - seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers); - seq_printf(seq, "Total size: %d kB\n", bytes / 1024); +static const char *rtn_type_names[__RTN_MAX] = { + [RTN_UNSPEC] = "UNSPEC", + [RTN_UNICAST] = "UNICAST", + [RTN_LOCAL] = "LOCAL", + [RTN_BROADCAST] = "BROADCAST", + [RTN_ANYCAST] = "ANYCAST", + [RTN_MULTICAST] = "MULTICAST", + [RTN_BLACKHOLE] = "BLACKHOLE", + [RTN_UNREACHABLE] = "UNREACHABLE", + [RTN_PROHIBIT] = "PROHIBIT", + [RTN_THROW] = "THROW", + [RTN_NAT] = "NAT", + [RTN_XRESOLVE] = "XRESOLVE", +}; - kfree(stat); - } +static inline const char *rtn_type(unsigned t) +{ + static char buf[32]; -#ifdef CONFIG_IP_FIB_TRIE_STATS - seq_printf(seq, "Counters:\n---------\n"); - seq_printf(seq,"gets = %d\n", t->stats.gets); - seq_printf(seq,"backtracks = %d\n", t->stats.backtrack); - seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed); - seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss); - seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit); - seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped); -#ifdef CLEAR_STATS - memset(&(t->stats), 0, sizeof(t->stats)); -#endif -#endif /* CONFIG_IP_FIB_TRIE_STATS */ + if (t < __RTN_MAX && rtn_type_names[t]) + return rtn_type_names[t]; + snprintf(buf, sizeof(buf), "type %d", t); + return buf; } -static int fib_triestat_seq_show(struct seq_file *seq, void *v) +/* Pretty print the trie */ +static int fib_trie_seq_show(struct seq_file *seq, void *v) { - char bf[128]; + const struct fib_trie_iter *iter = seq->private; + struct node *n = v; - if (v == SEQ_START_TOKEN) { - seq_printf(seq, "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n", - sizeof(struct leaf), sizeof(struct tnode)); - if (trie_local) - collect_and_show(trie_local, seq); + if (v == SEQ_START_TOKEN) + return 0; - if (trie_main) - collect_and_show(trie_main, seq); - } else { - snprintf(bf, sizeof(bf), "*\t%08X\t%08X", 200, 400); + if (IS_TNODE(n)) { + struct tnode *tn = (struct tnode *) n; + t_key prf = ntohl(MASK_PFX(tn->key, tn->pos)); - seq_printf(seq, "%-127s\n", bf); + if (!NODE_PARENT(n)) { + if (iter->trie == trie_local) + seq_puts(seq, "<local>:\n"); + else + seq_puts(seq, "<main>:\n"); + } else { + seq_indent(seq, iter->depth-1); + seq_printf(seq, " +-- %d.%d.%d.%d/%d\n", + NIPQUAD(prf), tn->pos); + } + } else { + struct leaf *l = (struct leaf *) n; + int i; + u32 val = ntohl(l->key); + + seq_indent(seq, iter->depth); + seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val)); + for (i = 32; i >= 0; i--) { + struct leaf_info *li = find_leaf_info(&l->list, i); + if (li) { + struct fib_alias *fa; + list_for_each_entry_rcu(fa, &li->falh, fa_list) { + seq_indent(seq, iter->depth+1); + seq_printf(seq, " /%d %s %s", i, + rtn_scope(fa->fa_scope), + rtn_type(fa->fa_type)); + if (fa->fa_tos) + seq_printf(seq, "tos =%d\n", + fa->fa_tos); + seq_putc(seq, '\n'); + } + } + } } + return 0; } -static struct seq_operations fib_triestat_seq_ops = { - .start = fib_triestat_seq_start, - .next = fib_triestat_seq_next, - .stop = fib_triestat_seq_stop, - .show = fib_triestat_seq_show, +static struct seq_operations fib_trie_seq_ops = { + .start = fib_trie_seq_start, + .next = fib_trie_seq_next, + .stop = fib_trie_seq_stop, + .show = fib_trie_seq_show, }; -static int fib_triestat_seq_open(struct inode *inode, struct file *file) +static int fib_trie_seq_open(struct inode *inode, struct file *file) { struct seq_file *seq; int rc = -ENOMEM; + struct fib_trie_iter *s = kmalloc(sizeof(*s), GFP_KERNEL); - rc = seq_open(file, &fib_triestat_seq_ops); + if (!s) + goto out; + + rc = seq_open(file, &fib_trie_seq_ops); if (rc) goto out_kfree; - seq = file->private_data; + seq = file->private_data; + seq->private = s; + memset(s, 0, sizeof(*s)); out: return rc; out_kfree: + kfree(s); goto out; } -static struct file_operations fib_triestat_seq_fops = { - .owner = THIS_MODULE, - .open = fib_triestat_seq_open, - .read = seq_read, - .llseek = seq_lseek, +static struct file_operations fib_trie_fops = { + .owner = THIS_MODULE, + .open = fib_trie_seq_open, + .read = seq_read, + .llseek = seq_lseek, .release = seq_release_private, }; -int __init fib_stat_proc_init(void) -{ - if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_seq_fops)) - return -ENOMEM; - return 0; -} - -void __init fib_stat_proc_exit(void) +static unsigned fib_flag_trans(int type, u32 mask, const struct fib_info *fi) { - proc_net_remove("fib_triestat"); -} + static unsigned type2flags[RTN_MAX + 1] = { + [7] = RTF_REJECT, [8] = RTF_REJECT, + }; + unsigned flags = type2flags[type]; -static struct fib_alias *fib_trie_get_first(struct seq_file *seq) -{ - return NULL; + if (fi && fi->fib_nh->nh_gw) + flags |= RTF_GATEWAY; + if (mask == 0xFFFFFFFF) + flags |= RTF_HOST; + flags |= RTF_UP; + return flags; } -static struct fib_alias *fib_trie_get_next(struct seq_file *seq) +/* + * This outputs /proc/net/route. + * The format of the file is not supposed to be changed + * and needs to be same as fib_hash output to avoid breaking + * legacy utilities + */ +static int fib_route_seq_show(struct seq_file *seq, void *v) { - return NULL; -} + struct leaf *l = v; + int i; + char bf[128]; -static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) -{ - if (!ip_fib_main_table) - return NULL; + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway " + "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU" + "\tWindow\tIRTT"); + return 0; + } - if (*pos) - return fib_trie_get_next(seq); - else - return SEQ_START_TOKEN; -} + if (IS_TNODE(l)) + return 0; -static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - if (v == SEQ_START_TOKEN) - return fib_trie_get_first(seq); - else - return fib_trie_get_next(seq); + for (i=32; i>=0; i--) { + struct leaf_info *li = find_leaf_info(&l->list, i); + struct fib_alias *fa; + u32 mask, prefix; -} + if (!li) + continue; -static void fib_trie_seq_stop(struct seq_file *seq, void *v) -{ -} + mask = inet_make_mask(li->plen); + prefix = htonl(l->key); -/* - * This outputs /proc/net/fib_trie. - * - * It always works in backward compatibility mode. - * The format of the file is not supposed to be changed. - */ + list_for_each_entry_rcu(fa, &li->falh, fa_list) { + const struct fib_info *fi = rcu_dereference(fa->fa_info); + unsigned flags = fib_flag_trans(fa->fa_type, mask, fi); -static int fib_trie_seq_show(struct seq_file *seq, void *v) -{ - char bf[128]; + if (fa->fa_type == RTN_BROADCAST + || fa->fa_type == RTN_MULTICAST) + continue; - if (v == SEQ_START_TOKEN) { - if (trie_local) - trie_dump_seq(seq, trie_local); + if (fi) + snprintf(bf, sizeof(bf), + "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", + fi->fib_dev ? fi->fib_dev->name : "*", + prefix, + fi->fib_nh->nh_gw, flags, 0, 0, + fi->fib_priority, + mask, + (fi->fib_advmss ? fi->fib_advmss + 40 : 0), + fi->fib_window, + fi->fib_rtt >> 3); + else + snprintf(bf, sizeof(bf), + "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", + prefix, 0, flags, 0, 0, 0, + mask, 0, 0, 0); - if (trie_main) - trie_dump_seq(seq, trie_main); - } else { - snprintf(bf, sizeof(bf), - "*\t%08X\t%08X", 200, 400); - seq_printf(seq, "%-127s\n", bf); + seq_printf(seq, "%-127s\n", bf); + } } return 0; } -static struct seq_operations fib_trie_seq_ops = { - .start = fib_trie_seq_start, - .next = fib_trie_seq_next, - .stop = fib_trie_seq_stop, - .show = fib_trie_seq_show, +static struct seq_operations fib_route_seq_ops = { + .start = fib_trie_seq_start, + .next = fib_trie_seq_next, + .stop = fib_trie_seq_stop, + .show = fib_route_seq_show, }; -static int fib_trie_seq_open(struct inode *inode, struct file *file) +static int fib_route_seq_open(struct inode *inode, struct file *file) { struct seq_file *seq; int rc = -ENOMEM; + struct fib_trie_iter *s = kmalloc(sizeof(*s), GFP_KERNEL); - rc = seq_open(file, &fib_trie_seq_ops); + if (!s) + goto out; + + rc = seq_open(file, &fib_route_seq_ops); if (rc) goto out_kfree; - seq = file->private_data; + seq = file->private_data; + seq->private = s; + memset(s, 0, sizeof(*s)); out: return rc; out_kfree: + kfree(s); goto out; } -static struct file_operations fib_trie_seq_fops = { - .owner = THIS_MODULE, - .open = fib_trie_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release= seq_release_private, +static struct file_operations fib_route_fops = { + .owner = THIS_MODULE, + .open = fib_route_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, }; int __init fib_proc_init(void) { - if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_seq_fops)) - return -ENOMEM; + if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_fops)) + goto out1; + + if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_fops)) + goto out2; + + if (!proc_net_fops_create("route", S_IRUGO, &fib_route_fops)) + goto out3; + return 0; + +out3: + proc_net_remove("fib_triestat"); +out2: + proc_net_remove("fib_trie"); +out1: + return -ENOMEM; } void __init fib_proc_exit(void) { proc_net_remove("fib_trie"); + proc_net_remove("fib_triestat"); + proc_net_remove("route"); } #endif /* CONFIG_PROC_FS */ -- GitLab From 5a0773698c51fdcec7eb361b6b819669ed1d249e Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 22:44:31 +0200 Subject: [PATCH 066/563] kbuild: cris use generic asm-offsets.h support Cris has a dedicated asm-offsets.c file per subarchitecture. So a symlink is created to put the desired asm-offsets.c file in $(ARCH)/kernel This is absolutely not good practice, but it was the trick used in the rest of the cris code. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/cris/Makefile | 10 ++-------- arch/cris/arch-v10/kernel/entry.S | 2 +- arch/cris/arch-v32/kernel/entry.S | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/arch/cris/Makefile b/arch/cris/Makefile index 90ca8730b1203..a00043a91f16c 100644 --- a/arch/cris/Makefile +++ b/arch/cris/Makefile @@ -107,8 +107,7 @@ archclean: rm -f timage vmlinux.bin decompress.bin rescue.bin cramfs.img rm -rf $(LD_SCRIPT).tmp -prepare: $(SRC_ARCH)/.links $(srctree)/include/asm-$(ARCH)/.arch \ - include/asm-$(ARCH)/$(SARCH)/offset.h +prepare: $(SRC_ARCH)/.links $(srctree)/include/asm-$(ARCH)/.arch # Create some links to make all tools happy $(SRC_ARCH)/.links: @@ -120,6 +119,7 @@ $(SRC_ARCH)/.links: @ln -sfn $(SRC_ARCH)/$(SARCH)/lib $(SRC_ARCH)/lib @ln -sfn $(SRC_ARCH)/$(SARCH) $(SRC_ARCH)/arch @ln -sfn $(SRC_ARCH)/$(SARCH)/vmlinux.lds.S $(SRC_ARCH)/kernel/vmlinux.lds.S + @ln -sfn $(SRC_ARCH)/$(SARCH)/asm-offsets.c $(SRC_ARCH)/kernel/asm-offsets.c @touch $@ # Create link to sub arch includes @@ -128,9 +128,3 @@ $(srctree)/include/asm-$(ARCH)/.arch: $(wildcard include/config/arch/*.h) @rm -f include/asm-$(ARCH)/arch @ln -sf $(srctree)/include/asm-$(ARCH)/$(SARCH) $(srctree)/include/asm-$(ARCH)/arch @touch $@ - -arch/$(ARCH)/$(SARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ - include/config/MARKER - -include/asm-$(ARCH)/$(SARCH)/offset.h: arch/$(ARCH)/$(SARCH)/kernel/asm-offsets.s - $(call filechk,gen-asm-offsets) diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index c0163bf94a500..c808005e84578 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -270,7 +270,7 @@ #include <asm/arch/sv_addr_ag.h> #include <asm/errno.h> #include <asm/thread_info.h> -#include <asm/arch/offset.h> +#include <asm/asm-offsets.h> #include <asm/page.h> #include <asm/pgtable.h> diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index a8ed55e5b4031..3bd8503fec684 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S @@ -23,7 +23,7 @@ #include <asm/unistd.h> #include <asm/errno.h> #include <asm/thread_info.h> -#include <asm/arch/offset.h> +#include <asm/asm-offsets.h> #include <asm/arch/hwregs/asm/reg_map_asm.h> #include <asm/arch/hwregs/asm/intr_vect_defs_asm.h> -- GitLab From 1325cc79163058739b70bed9860fccbecac6236b Mon Sep 17 00:00:00 2001 From: Hal Rosenstock <halr@voltaire.com> Date: Fri, 9 Sep 2005 13:45:51 -0700 Subject: [PATCH 067/563] [PATCH] IB: Define more SA methods ib_sa.h: Define more SA methods (initially for madeye decode) Signed-off-by: Hal Rosenstock <halr@voltaire.com> Signed-off-by: Roland Dreier <rolandd@cisco.com> --- include/rdma/ib_sa.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index c022edfc49da0..0f4f5ec85e82a 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -46,7 +46,11 @@ enum { IB_SA_METHOD_GET_TABLE = 0x12, IB_SA_METHOD_GET_TABLE_RESP = 0x92, - IB_SA_METHOD_DELETE = 0x15 + IB_SA_METHOD_DELETE = 0x15, + IB_SA_METHOD_DELETE_RESP = 0x95, + IB_SA_METHOD_GET_MULTI = 0x14, + IB_SA_METHOD_GET_MULTI_RESP = 0x94, + IB_SA_METHOD_GET_TRACE_TBL = 0x13 }; enum ib_sa_selector { -- GitLab From 0037c78a96bb391635bff103d401c24459c5092d Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 22:47:53 +0200 Subject: [PATCH 068/563] kbuild: frv,m32r,sparc64 introduce fake asm-offsets.h file Needed to get them to build. And a hint to avoid hardcoding to many constants in assembler. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/frv/kernel/asm-offsets.c | 1 + arch/m32r/kernel/asm-offsets.c | 1 + arch/sparc64/kernel/asm-offsets.c | 1 + 3 files changed, 3 insertions(+) create mode 100644 arch/frv/kernel/asm-offsets.c create mode 100644 arch/m32r/kernel/asm-offsets.c create mode 100644 arch/sparc64/kernel/asm-offsets.c diff --git a/arch/frv/kernel/asm-offsets.c b/arch/frv/kernel/asm-offsets.c new file mode 100644 index 0000000000000..9e263112a6e2f --- /dev/null +++ b/arch/frv/kernel/asm-offsets.c @@ -0,0 +1 @@ +/* Dummy asm-offsets.c file. Required by kbuild and ready to be used - hint! */ diff --git a/arch/m32r/kernel/asm-offsets.c b/arch/m32r/kernel/asm-offsets.c new file mode 100644 index 0000000000000..9e263112a6e2f --- /dev/null +++ b/arch/m32r/kernel/asm-offsets.c @@ -0,0 +1 @@ +/* Dummy asm-offsets.c file. Required by kbuild and ready to be used - hint! */ diff --git a/arch/sparc64/kernel/asm-offsets.c b/arch/sparc64/kernel/asm-offsets.c new file mode 100644 index 0000000000000..9e263112a6e2f --- /dev/null +++ b/arch/sparc64/kernel/asm-offsets.c @@ -0,0 +1 @@ +/* Dummy asm-offsets.c file. Required by kbuild and ready to be used - hint! */ -- GitLab From 1299232b5743da454c73853b90b3d2d83dce1737 Mon Sep 17 00:00:00 2001 From: Andrew Morton <akpm@osdl.org> Date: Fri, 9 Sep 2005 13:01:21 -0700 Subject: [PATCH 069/563] [PATCH] x86: MP_processor_info fix Remove the weird and apparently unnecessary logic in MP_processor_info() which assumes that the BSP is the first one to run MP_processor_info(). On one of my boxes that isn't true and cpu_possible_map gets the wrong value. Cc: Zwane Mwaikambo <zwane@arm.linux.org.uk> Cc: Alexander Nyberg <alexn@telia.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/kernel/mpparse.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index cafaeffe38185..15949fd081095 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -122,8 +122,8 @@ static int MP_valid_apicid(int apicid, int version) static void __init MP_processor_info (struct mpc_config_processor *m) { - int ver, apicid, cpu, found_bsp = 0; - physid_mask_t tmp; + int ver, apicid; + physid_mask_t phys_cpu; if (!(m->mpc_cpuflag & CPU_ENABLED)) return; @@ -181,7 +181,6 @@ static void __init MP_processor_info (struct mpc_config_processor *m) if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { Dprintk(" Bootup CPU\n"); boot_cpu_physical_apicid = m->mpc_apicid; - found_bsp = 1; } if (num_processors >= NR_CPUS) { @@ -195,29 +194,26 @@ static void __init MP_processor_info (struct mpc_config_processor *m) " Processor ignored.\n", maxcpus); return; } - num_processors++; ver = m->mpc_apicver; if (!MP_valid_apicid(apicid, ver)) { printk(KERN_WARNING "Processor #%d INVALID. (Max ID: %d).\n", m->mpc_apicid, MAX_APICS); - --num_processors; return; } - if (found_bsp) - cpu = 0; - else - cpu = num_processors - 1; - cpu_set(cpu, cpu_possible_map); - tmp = apicid_to_cpu_present(apicid); - physids_or(phys_cpu_present_map, phys_cpu_present_map, tmp); - + cpu_set(num_processors, cpu_possible_map); + num_processors++; + phys_cpu = apicid_to_cpu_present(apicid); + physids_or(phys_cpu_present_map, phys_cpu_present_map, phys_cpu); + /* * Validate version */ if (ver == 0x0) { - printk(KERN_WARNING "BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); + printk(KERN_WARNING "BIOS bug, APIC version is 0 for CPU#%d! " + "fixing up to 0x10. (tell your hw vendor)\n", + m->mpc_apicid); ver = 0x10; } apic_version[m->mpc_apicid] = ver; -- GitLab From 4b5d37ac02954572e80e09255bb5737277aaee8e Mon Sep 17 00:00:00 2001 From: Giancarlo Formicuccia <giancarlo.formicuccia@gmail.com> Date: Fri, 9 Sep 2005 13:01:22 -0700 Subject: [PATCH 070/563] [PATCH] Clear task_struct->fs_excl on fork() An oversight. We don't want to carry the IO scheduler's "we hold exclusive fs resources" hint over to the child across fork(). Acked-by: Jens Axboe <axboe@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/fork.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/fork.c b/kernel/fork.c index 7e1ead9a6ba45..dfeadf466f185 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -176,6 +176,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) /* One for us, one for whoever does the "release_task()" (usually parent) */ atomic_set(&tsk->usage,2); + atomic_set(&tsk->fs_excl, 0); return tsk; } -- GitLab From abda24528ac3045511fb59291a2d6ccbddf30eda Mon Sep 17 00:00:00 2001 From: Magnus Damm <magnus@valinux.co.jp> Date: Fri, 9 Sep 2005 13:01:23 -0700 Subject: [PATCH 071/563] [PATCH] i386: CONFIG_ACPI_SRAT typo fix Fix a typo involving CONFIG_ACPI_SRAT. Signed-off-by: Magnus Damm <magnus@valinux.co.jp> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-i386/mmzone.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h index 516421300ea2d..348fe3a4879dd 100644 --- a/include/asm-i386/mmzone.h +++ b/include/asm-i386/mmzone.h @@ -29,7 +29,7 @@ static inline void get_memcfg_numa(void) #ifdef CONFIG_X86_NUMAQ if (get_memcfg_numaq()) return; -#elif CONFIG_ACPI_SRAT +#elif defined(CONFIG_ACPI_SRAT) if (get_memcfg_from_srat()) return; #endif -- GitLab From 7f6fd5db2dbc28d475d67f9a6b041fefe1d6f7c8 Mon Sep 17 00:00:00 2001 From: Kumar Gala <galak@freescale.com> Date: Fri, 9 Sep 2005 13:01:26 -0700 Subject: [PATCH 072/563] [PATCH] ppc32: Fix Kconfig mismerge Looks like the help comment for MPC834x got merged incorrectly. Signed-off-by: Kumar Gala <kumar.gala@freescale.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ppc/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 6ab7e5ea5fcfd..e3f1ce33e6425 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -499,11 +499,6 @@ config WINCEPT MPC821 PowerPC, introduced in 1998 and designed to be used in thin-client machines. Say Y to support it directly. - Be aware that PCI buses can only function when SYS board is plugged - into the PIB (Platform IO Board) board from Freescale which provide - 3 PCI slots. The PIBs PCI initialization is the bootloader's - responsiblilty. - endchoice choice @@ -680,6 +675,11 @@ config MPC834x_SYS help This option enables support for the MPC 834x SYS evaluation board. + Be aware that PCI buses can only function when SYS board is plugged + into the PIB (Platform IO Board) board from Freescale which provide + 3 PCI slots. The PIBs PCI initialization is the bootloader's + responsiblilty. + config EV64360 bool "Marvell-EV64360BP" help -- GitLab From e85b565233236a2a833adea73fb2f0e0f8fa2a61 Mon Sep 17 00:00:00 2001 From: Mark Fasheh <mark.fasheh@oracle.com> Date: Fri, 9 Sep 2005 13:01:29 -0700 Subject: [PATCH 073/563] [PATCH] move truncate_inode_pages() into ->delete_inode() Allow file systems supporting ->delete_inode() to call truncate_inode_pages() on their own. OCFS2 wants this so it can query the cluster before making a final decision on whether to wipe an inode from disk or not. In some corner cases an inode marked on the local node via voting may not actually get orphaned. A good example is node death before the transaction moving the inode to the orphan dir commits to the journal. Without this patch, the truncate_inode_pages() call in generic_delete_inode() would discard valid data for such inodes. During earlier discussion in the 2.6.13 merge plan thread, Christoph Hellwig indicated that other file systems might also find this useful. IMHO, the best solution would be to just allow ->drop_inode() to do the cluster query but it seems that would require a substantial reworking of that section of the code. Assuming it is safe to call write_inode_now() in ocfs2_delete_inode() for those inodes which won't actually get wiped, this solution should get us by for now. Trivial testing of this patch (and a related OCFS2 update) has shown this to avoid the corruption I'm seeing. Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com> Acked-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/inode.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/inode.c b/fs/inode.c index 71df1b1e8f75a..f80a79ff156b5 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1034,19 +1034,21 @@ void generic_delete_inode(struct inode *inode) inodes_stat.nr_inodes--; spin_unlock(&inode_lock); - if (inode->i_data.nrpages) - truncate_inode_pages(&inode->i_data, 0); - security_inode_delete(inode); if (op->delete_inode) { void (*delete)(struct inode *) = op->delete_inode; if (!is_bad_inode(inode)) DQUOT_INIT(inode); - /* s_op->delete_inode internally recalls clear_inode() */ + /* Filesystems implementing their own + * s_op->delete_inode are required to call + * truncate_inode_pages and clear_inode() + * internally */ delete(inode); - } else + } else { + truncate_inode_pages(&inode->i_data, 0); clear_inode(inode); + } spin_lock(&inode_lock); hlist_del_init(&inode->i_hash); spin_unlock(&inode_lock); -- GitLab From fef266580e5cf897a1b63528fc6b1185e2d6bb87 Mon Sep 17 00:00:00 2001 From: Mark Fasheh <mark.fasheh@oracle.com> Date: Fri, 9 Sep 2005 13:01:31 -0700 Subject: [PATCH 074/563] [PATCH] update filesystems for new delete_inode behavior Update the file systems in fs/ implementing a delete_inode() callback to call truncate_inode_pages(). One implementation note: In developing this patch I put the calls to truncate_inode_pages() at the very top of those filesystems delete_inode() callbacks in order to retain the previous behavior. I'm guessing that some of those could probably be optimized. Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com> Acked-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/affs/inode.c | 1 + fs/bfs/inode.c | 2 ++ fs/ext2/inode.c | 2 ++ fs/ext3/inode.c | 2 ++ fs/fat/inode.c | 2 ++ fs/hostfs/hostfs_kern.c | 1 + fs/hpfs/inode.c | 1 + fs/jffs/inode-v23.c | 1 + fs/jfs/inode.c | 2 ++ fs/minix/inode.c | 1 + fs/ncpfs/inode.c | 2 ++ fs/nfs/inode.c | 2 ++ fs/proc/inode.c | 2 ++ fs/qnx4/inode.c | 1 + fs/reiserfs/inode.c | 2 ++ fs/smbfs/inode.c | 1 + fs/sysv/inode.c | 1 + fs/udf/inode.c | 2 ++ fs/ufs/inode.c | 1 + mm/shmem.c | 1 + 20 files changed, 30 insertions(+) diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 7aa6f2004536d..9ebe881c67864 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -255,6 +255,7 @@ void affs_delete_inode(struct inode *inode) { pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); + truncate_inode_pages(&inode->i_data, 0); inode->i_size = 0; if (S_ISREG(inode->i_mode)) affs_truncate(inode); diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 64e0fb33fc0ca..628c2c1a7d7e4 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -143,6 +143,8 @@ static void bfs_delete_inode(struct inode * inode) dprintf("ino=%08lx\n", inode->i_ino); + truncate_inode_pages(&inode->i_data, 0); + if (inode->i_ino < BFS_ROOT_INO || inode->i_ino > info->si_lasti) { printf("invalid ino=%08lx\n", inode->i_ino); return; diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 53dceb0c65930..fdba4d1d3c609 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -71,6 +71,8 @@ void ext2_put_inode(struct inode *inode) */ void ext2_delete_inode (struct inode * inode) { + truncate_inode_pages(&inode->i_data, 0); + if (is_bad_inode(inode)) goto no_delete; EXT2_I(inode)->i_dtime = get_seconds(); diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 9989fdcf4d5ab..b5177c90d6f11 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -187,6 +187,8 @@ void ext3_delete_inode (struct inode * inode) { handle_t *handle; + truncate_inode_pages(&inode->i_data, 0); + if (is_bad_inode(inode)) goto no_delete; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 96ae85b67eba6..a7cbe68e22596 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -335,6 +335,8 @@ EXPORT_SYMBOL(fat_build_inode); static void fat_delete_inode(struct inode *inode) { + truncate_inode_pages(&inode->i_data, 0); + if (!is_bad_inode(inode)) { inode->i_size = 0; fat_truncate(inode); diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index b2d18200a003f..59c5062cd63f3 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -284,6 +284,7 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb) static void hostfs_delete_inode(struct inode *inode) { + truncate_inode_pages(&inode->i_data, 0); if(HOSTFS_I(inode)->fd != -1) { close_file(&HOSTFS_I(inode)->fd); HOSTFS_I(inode)->fd = -1; diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 38b1741fa539f..e3d17e9ea6c19 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -284,6 +284,7 @@ void hpfs_write_if_changed(struct inode *inode) void hpfs_delete_inode(struct inode *inode) { + truncate_inode_pages(&inode->i_data, 0); lock_kernel(); hpfs_remove_fnode(inode->i_sb, inode->i_ino); unlock_kernel(); diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 777b90057b893..3dcc6d2162cb8 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -1744,6 +1744,7 @@ jffs_delete_inode(struct inode *inode) D3(printk("jffs_delete_inode(): inode->i_ino == %lu\n", inode->i_ino)); + truncate_inode_pages(&inode->i_data, 0); lock_kernel(); inode->i_size = 0; inode->i_blocks = 0; diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 767c7ecb429ed..cff352f4ec18d 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -132,6 +132,8 @@ void jfs_delete_inode(struct inode *inode) (JFS_IP(inode)->fileset != cpu_to_le32(FILESYSTEM_I))) return; + truncate_inode_pages(&inode->i_data, 0); + if (test_cflag(COMMIT_Freewmap, inode)) jfs_free_zero_link(inode); diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 3f18c21198d7e..790cc0d0e970a 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -24,6 +24,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data); static void minix_delete_inode(struct inode *inode) { + truncate_inode_pages(&inode->i_data, 0); inode->i_size = 0; minix_truncate(inode); minix_free_inode(inode); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 44795d2f4b308..8c8839203cd5a 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -286,6 +286,8 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info) static void ncp_delete_inode(struct inode *inode) { + truncate_inode_pages(&inode->i_data, 0); + if (S_ISDIR(inode->i_mode)) { DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino); } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 541b418327c8b..6922469d6fc57 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -146,6 +146,8 @@ nfs_delete_inode(struct inode * inode) { dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); + truncate_inode_pages(&inode->i_data, 0); + nfs_wb_all(inode); /* * The following should never happen... diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 133c286851056..effa6c0c467ac 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -60,6 +60,8 @@ static void proc_delete_inode(struct inode *inode) struct proc_dir_entry *de; struct task_struct *tsk; + truncate_inode_pages(&inode->i_data, 0); + /* Let go of any associated process */ tsk = PROC_I(inode)->task; if (tsk) diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index b79162a35478c..80f32911c0cb4 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -63,6 +63,7 @@ int qnx4_sync_inode(struct inode *inode) static void qnx4_delete_inode(struct inode *inode) { QNX4DEBUG(("qnx4: deleting inode [%lu]\n", (unsigned long) inode->i_ino)); + truncate_inode_pages(&inode->i_data, 0); inode->i_size = 0; qnx4_truncate(inode); lock_kernel(); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index ff291c973a567..1a8a1bf2154d1 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -33,6 +33,8 @@ void reiserfs_delete_inode(struct inode *inode) 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); struct reiserfs_transaction_handle th; + truncate_inode_pages(&inode->i_data, 0); + reiserfs_write_lock(inode->i_sb); /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */ diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 4765aaac9fd2c..10b994428fef2 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -331,6 +331,7 @@ static void smb_delete_inode(struct inode *ino) { DEBUG1("ino=%ld\n", ino->i_ino); + truncate_inode_pages(&ino->i_data, 0); lock_kernel(); if (smb_close(ino)) PARANOIA("could not close inode %ld\n", ino->i_ino); diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 0530077d9dd80..fa33eceb00113 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -292,6 +292,7 @@ int sysv_sync_inode(struct inode * inode) static void sysv_delete_inode(struct inode *inode) { + truncate_inode_pages(&inode->i_data, 0); inode->i_size = 0; sysv_truncate(inode); lock_kernel(); diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 3d68de39fad62..b83890beaaacb 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -87,6 +87,8 @@ static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); */ void udf_delete_inode(struct inode * inode) { + truncate_inode_pages(&inode->i_data, 0); + if (is_bad_inode(inode)) goto no_delete; diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 718627ca8b5c6..55f4aa16e3fc9 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -804,6 +804,7 @@ int ufs_sync_inode (struct inode *inode) void ufs_delete_inode (struct inode * inode) { + truncate_inode_pages(&inode->i_data, 0); /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/ lock_kernel(); mark_inode_dirty(inode); diff --git a/mm/shmem.c b/mm/shmem.c index db2c9e8d99095..0d627a37da954 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -666,6 +666,7 @@ static void shmem_delete_inode(struct inode *inode) struct shmem_inode_info *info = SHMEM_I(inode); if (inode->i_op->truncate == shmem_truncate) { + truncate_inode_pages(inode->i_mapping, 0); shmem_unacct_size(info->flags, inode->i_size); inode->i_size = 0; shmem_truncate(inode); -- GitLab From f5ee56cc184e0944ebc9ff1691985219959596f6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle <ralf@linux-mips.org> Date: Fri, 9 Sep 2005 13:01:32 -0700 Subject: [PATCH 075/563] [PATCH] txx9 serial update Support for the new RBHMA4500 eval board for the TX4938. General update from the 8250 ancestor of this driver. Replace use of deprecated interfaces. Signed-off-by: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Acked-by: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/serial/serial_txx9.c | 118 +++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 27 deletions(-) diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 49afadbe461b2..f10c86d60b647 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -31,6 +31,8 @@ * 1.01 Set fifosize to make tx_empry called properly. * Use standard uart_get_divisor. * 1.02 Cleanup. (import 8250.c changes) + * 1.03 Fix low-latency mode. (import 8250.c changes) + * 1.04 Remove usage of deprecated functions, cleanup. */ #include <linux/config.h> @@ -54,7 +56,7 @@ #include <asm/io.h> #include <asm/irq.h> -static char *serial_version = "1.02"; +static char *serial_version = "1.04"; static char *serial_name = "TX39/49 Serial driver"; #define PASS_LIMIT 256 @@ -86,9 +88,9 @@ static char *serial_name = "TX39/49 Serial driver"; */ #ifdef ENABLE_SERIAL_TXX9_PCI #define NR_PCI_BOARDS 4 -#define UART_NR (2 + NR_PCI_BOARDS) +#define UART_NR (4 + NR_PCI_BOARDS) #else -#define UART_NR 2 +#define UART_NR 4 #endif struct uart_txx9_port { @@ -304,8 +306,11 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r /* The following is not allowed by the tty layer and unsafe. It should be fixed ASAP */ if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { - if(tty->low_latency) + if (tty->low_latency) { + spin_unlock(&up->port.lock); tty_flip_buffer_push(tty); + spin_lock(&up->port.lock); + } /* If this failed then we will throw away the bytes but must do so to clear interrupts */ } @@ -356,7 +361,9 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r ignore_char: disr = sio_in(up, TXX9_SIDISR); } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); + spin_unlock(&up->port.lock); tty_flip_buffer_push(tty); + spin_lock(&up->port.lock); *status = disr; } @@ -667,17 +674,8 @@ serial_txx9_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct uart_txx9_port *up = (struct uart_txx9_port *)port; - if (state) { - /* sleep */ - - if (up->pm) - up->pm(port, state, oldstate); - } else { - /* wake */ - - if (up->pm) - up->pm(port, state, oldstate); - } + if (up->pm) + up->pm(port, state, oldstate); } static int serial_txx9_request_resource(struct uart_txx9_port *up) @@ -979,14 +977,6 @@ static int __init serial_txx9_console_init(void) } console_initcall(serial_txx9_console_init); -static int __init serial_txx9_late_console_init(void) -{ - if (!(serial_txx9_console.flags & CON_ENABLED)) - register_console(&serial_txx9_console); - return 0; -} -late_initcall(serial_txx9_late_console_init); - #define SERIAL_TXX9_CONSOLE &serial_txx9_console #else #define SERIAL_TXX9_CONSOLE NULL @@ -1039,6 +1029,73 @@ static void serial_txx9_resume_port(int line) uart_resume_port(&serial_txx9_reg, &serial_txx9_ports[line].port); } +static DECLARE_MUTEX(serial_txx9_sem); + +/** + * serial_txx9_register_port - register a serial port + * @port: serial port template + * + * Configure the serial port specified by the request. + * + * The port is then probed and if necessary the IRQ is autodetected + * If this fails an error is returned. + * + * On success the port is ready to use and the line number is returned. + */ +static int __devinit serial_txx9_register_port(struct uart_port *port) +{ + int i; + struct uart_txx9_port *uart; + int ret = -ENOSPC; + + down(&serial_txx9_sem); + for (i = 0; i < UART_NR; i++) { + uart = &serial_txx9_ports[i]; + if (uart->port.type == PORT_UNKNOWN) + break; + } + if (i < UART_NR) { + uart_remove_one_port(&serial_txx9_reg, &uart->port); + uart->port.iobase = port->iobase; + uart->port.membase = port->membase; + uart->port.irq = port->irq; + uart->port.uartclk = port->uartclk; + uart->port.iotype = port->iotype; + uart->port.flags = port->flags | UPF_BOOT_AUTOCONF; + uart->port.mapbase = port->mapbase; + if (port->dev) + uart->port.dev = port->dev; + ret = uart_add_one_port(&serial_txx9_reg, &uart->port); + if (ret == 0) + ret = uart->port.line; + } + up(&serial_txx9_sem); + return ret; +} + +/** + * serial_txx9_unregister_port - remove a txx9 serial port at runtime + * @line: serial line number + * + * Remove one serial port. This may not be called from interrupt + * context. We hand the port back to the our control. + */ +static void __devexit serial_txx9_unregister_port(int line) +{ + struct uart_txx9_port *uart = &serial_txx9_ports[line]; + + down(&serial_txx9_sem); + uart_remove_one_port(&serial_txx9_reg, &uart->port); + uart->port.flags = 0; + uart->port.type = PORT_UNKNOWN; + uart->port.iobase = 0; + uart->port.mapbase = 0; + uart->port.membase = 0; + uart->port.dev = NULL; + uart_add_one_port(&serial_txx9_reg, &uart->port); + up(&serial_txx9_sem); +} + /* * Probe one serial board. Unfortunately, there is no rhyme nor reason * to the arrangement of serial ports on a PCI card. @@ -1056,13 +1113,13 @@ pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent) memset(&port, 0, sizeof(port)); port.ops = &serial_txx9_pops; - port.flags |= UPF_BOOT_AUTOCONF; /* uart_ops.config_port will be called */ port.flags |= UPF_TXX9_HAVE_CTS_LINE; port.uartclk = 66670000; port.irq = dev->irq; port.iotype = UPIO_PORT; port.iobase = pci_resource_start(dev, 1); - line = uart_register_port(&serial_txx9_reg, &port); + port.dev = &dev->dev; + line = serial_txx9_register_port(&port); if (line < 0) { printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line); } @@ -1078,7 +1135,7 @@ static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev) pci_set_drvdata(dev, NULL); if (line) { - uart_unregister_port(&serial_txx9_reg, line); + serial_txx9_unregister_port(line); pci_disable_device(dev); } } @@ -1089,6 +1146,8 @@ static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) if (line) serial_txx9_suspend_port(line); + pci_save_state(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; } @@ -1096,8 +1155,13 @@ static int pciserial_txx9_resume_one(struct pci_dev *dev) { int line = (int)(long)pci_get_drvdata(dev); - if (line) + pci_set_power_state(dev, PCI_D0); + pci_restore_state(dev); + + if (line) { + pci_enable_device(dev); serial_txx9_resume_port(line); + } return 0; } -- GitLab From 5e41ff9e0650f327a6c819841fa412da95d57319 Mon Sep 17 00:00:00 2001 From: Stephen Smalley <sds@tycho.nsa.gov> Date: Fri, 9 Sep 2005 13:01:35 -0700 Subject: [PATCH 076/563] [PATCH] security: enable atomic inode security labeling The following patch set enables atomic security labeling of newly created inodes by altering the fs code to invoke a new LSM hook to obtain the security attribute to apply to a newly created inode and to set up the incore inode security state during the inode creation transaction. This parallels the existing processing for setting ACLs on newly created inodes. Otherwise, it is possible for new inodes to be accessed by another thread via the dcache prior to complete security setup (presently handled by the post_create/mkdir/... LSM hooks in the VFS) and a newly created inode may be left unlabeled on the disk in the event of a crash. SELinux presently works around the issue by ensuring that the incore inode security label is initialized to a special SID that is inaccessible to unprivileged processes (in accordance with policy), thereby preventing inappropriate access but potentially causing false denials on legitimate accesses. A simple test program demonstrates such false denials on SELinux, and the patch solves the problem. Similar such false denials have been encountered in real applications. This patch defines a new inode_init_security LSM hook to obtain the security attribute to apply to a newly created inode and to set up the incore inode security state for it, and adds a corresponding hook function implementation to SELinux. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/security.h | 41 +++++++++++++++++++++ security/dummy.c | 7 ++++ security/selinux/hooks.c | 59 +++++++++++++++++++++++++++++++ security/selinux/include/objsec.h | 1 + 4 files changed, 108 insertions(+) diff --git a/include/linux/security.h b/include/linux/security.h index 7aab6ab7c57fe..d4f3b7a94ea6e 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -250,6 +250,25 @@ struct swap_info_struct; * @inode contains the inode structure. * Deallocate the inode security structure and set @inode->i_security to * NULL. + * @inode_init_security: + * Obtain the security attribute name suffix and value to set on a newly + * created inode and set up the incore security field for the new inode. + * This hook is called by the fs code as part of the inode creation + * transaction and provides for atomic labeling of the inode, unlike + * the post_create/mkdir/... hooks called by the VFS. The hook function + * is expected to allocate the name and value via kmalloc, with the caller + * being responsible for calling kfree after using them. + * If the security module does not use security attributes or does + * not wish to put a security attribute on this particular inode, + * then it should return -EOPNOTSUPP to skip this processing. + * @inode contains the inode structure of the newly created inode. + * @dir contains the inode structure of the parent directory. + * @name will be set to the allocated name suffix (e.g. selinux). + * @value will be set to the allocated attribute value. + * @len will be set to the length of the value. + * Returns 0 if @name and @value have been successfully set, + * -EOPNOTSUPP if no security attribute is needed, or + * -ENOMEM on memory allocation failure. * @inode_create: * Check permission to create a regular file. * @dir contains inode structure of the parent of the new file. @@ -1080,6 +1099,8 @@ struct security_operations { int (*inode_alloc_security) (struct inode *inode); void (*inode_free_security) (struct inode *inode); + int (*inode_init_security) (struct inode *inode, struct inode *dir, + char **name, void **value, size_t *len); int (*inode_create) (struct inode *dir, struct dentry *dentry, int mode); void (*inode_post_create) (struct inode *dir, @@ -1442,6 +1463,17 @@ static inline void security_inode_free (struct inode *inode) return; security_ops->inode_free_security (inode); } + +static inline int security_inode_init_security (struct inode *inode, + struct inode *dir, + char **name, + void **value, + size_t *len) +{ + if (unlikely (IS_PRIVATE (inode))) + return -EOPNOTSUPP; + return security_ops->inode_init_security (inode, dir, name, value, len); +} static inline int security_inode_create (struct inode *dir, struct dentry *dentry, @@ -2171,6 +2203,15 @@ static inline int security_inode_alloc (struct inode *inode) static inline void security_inode_free (struct inode *inode) { } + +static inline int security_inode_init_security (struct inode *inode, + struct inode *dir, + char **name, + void **value, + size_t *len) +{ + return -EOPNOTSUPP; +} static inline int security_inode_create (struct inode *dir, struct dentry *dentry, diff --git a/security/dummy.c b/security/dummy.c index 6ff8875864795..e8a00fa804699 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -258,6 +258,12 @@ static void dummy_inode_free_security (struct inode *inode) return; } +static int dummy_inode_init_security (struct inode *inode, struct inode *dir, + char **name, void **value, size_t *len) +{ + return -EOPNOTSUPP; +} + static int dummy_inode_create (struct inode *inode, struct dentry *dentry, int mask) { @@ -886,6 +892,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, sb_post_pivotroot); set_to_dummy_if_null(ops, inode_alloc_security); set_to_dummy_if_null(ops, inode_free_security); + set_to_dummy_if_null(ops, inode_init_security); set_to_dummy_if_null(ops, inode_create); set_to_dummy_if_null(ops, inode_post_create); set_to_dummy_if_null(ops, inode_link); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8641f8894b4c0..63701fe0e1ad6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1274,6 +1274,7 @@ static int post_create(struct inode *dir, struct inode *inode; struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; + struct inode_security_struct *isec; u32 newsid; char *context; unsigned int len; @@ -1293,6 +1294,11 @@ static int post_create(struct inode *dir, return 0; } + isec = inode->i_security; + + if (isec->security_attr_init) + return 0; + if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { newsid = tsec->create_sid; } else { @@ -2018,6 +2024,58 @@ static void selinux_inode_free_security(struct inode *inode) inode_free_security(inode); } +static int selinux_inode_init_security(struct inode *inode, struct inode *dir, + char **name, void **value, + size_t *len) +{ + struct task_security_struct *tsec; + struct inode_security_struct *dsec; + struct superblock_security_struct *sbsec; + struct inode_security_struct *isec; + u32 newsid; + int rc; + char *namep, *context; + + tsec = current->security; + dsec = dir->i_security; + sbsec = dir->i_sb->s_security; + isec = inode->i_security; + + if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { + newsid = tsec->create_sid; + } else { + rc = security_transition_sid(tsec->sid, dsec->sid, + inode_mode_to_security_class(inode->i_mode), + &newsid); + if (rc) { + printk(KERN_WARNING "%s: " + "security_transition_sid failed, rc=%d (dev=%s " + "ino=%ld)\n", + __FUNCTION__, + -rc, inode->i_sb->s_id, inode->i_ino); + return rc; + } + } + + inode_security_set_sid(inode, newsid); + + namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL); + if (!namep) + return -ENOMEM; + *name = namep; + + rc = security_sid_to_context(newsid, &context, len); + if (rc) { + kfree(namep); + return rc; + } + *value = context; + + isec->security_attr_init = 1; + + return 0; +} + static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask) { return may_create(dir, dentry, SECCLASS_FILE); @@ -4298,6 +4356,7 @@ static struct security_operations selinux_ops = { .inode_alloc_security = selinux_inode_alloc_security, .inode_free_security = selinux_inode_free_security, + .inode_init_security = selinux_inode_init_security, .inode_create = selinux_inode_create, .inode_post_create = selinux_inode_post_create, .inode_link = selinux_inode_link, diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 887937c8134a4..c515bc0b58a1a 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -46,6 +46,7 @@ struct inode_security_struct { unsigned char initialized; /* initialization flag */ struct semaphore sem; unsigned char inherit; /* inherit SID from parent entry */ + unsigned char security_attr_init; /* security attributes init flag */ }; struct file_security_struct { -- GitLab From 10f47e6a1b8b276323b652053945c87a63a5812d Mon Sep 17 00:00:00 2001 From: Stephen Smalley <sds@tycho.nsa.gov> Date: Fri, 9 Sep 2005 13:01:39 -0700 Subject: [PATCH 077/563] [PATCH] ext2: Enable atomic inode security labeling This patch modifies ext2 to call the inode_init_security LSM hook to obtain the security attribute for a newly created inode and to set the resulting attribute on the new inode. This parallels the existing processing for setting ACLs on newly created inodes. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/ext2/ialloc.c | 5 +++++ fs/ext2/xattr.h | 8 ++++++++ fs/ext2/xattr_security.c | 22 ++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 161f156d98c86..c8d07030c8972 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -615,6 +615,11 @@ struct inode *ext2_new_inode(struct inode *dir, int mode) DQUOT_DROP(inode); goto fail2; } + err = ext2_init_security(inode,dir); + if (err) { + DQUOT_FREE_INODE(inode); + goto fail2; + } mark_inode_dirty(inode); ext2_debug("allocating inode %lu\n", inode->i_ino); ext2_preread_inode(inode); diff --git a/fs/ext2/xattr.h b/fs/ext2/xattr.h index 5f3bfde3b8100..67cfeb66e8973 100644 --- a/fs/ext2/xattr.h +++ b/fs/ext2/xattr.h @@ -116,3 +116,11 @@ exit_ext2_xattr(void) # endif /* CONFIG_EXT2_FS_XATTR */ +#ifdef CONFIG_EXT2_FS_SECURITY +extern int ext2_init_security(struct inode *inode, struct inode *dir); +#else +static inline int ext2_init_security(struct inode *inode, struct inode *dir) +{ + return 0; +} +#endif diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c index 6a6c59fbe5995..a26612798471c 100644 --- a/fs/ext2/xattr_security.c +++ b/fs/ext2/xattr_security.c @@ -8,6 +8,7 @@ #include <linux/fs.h> #include <linux/smp_lock.h> #include <linux/ext2_fs.h> +#include <linux/security.h> #include "xattr.h" static size_t @@ -45,6 +46,27 @@ ext2_xattr_security_set(struct inode *inode, const char *name, value, size, flags); } +int +ext2_init_security(struct inode *inode, struct inode *dir) +{ + int err; + size_t len; + void *value; + char *name; + + err = security_inode_init_security(inode, dir, &name, &value, &len); + if (err) { + if (err == -EOPNOTSUPP) + return 0; + return err; + } + err = ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY, + name, value, len, 0); + kfree(name); + kfree(value); + return err; +} + struct xattr_handler ext2_xattr_security_handler = { .prefix = XATTR_SECURITY_PREFIX, .list = ext2_xattr_security_list, -- GitLab From ac50960afa31877493add6d941d8402fa879c452 Mon Sep 17 00:00:00 2001 From: Stephen Smalley <sds@tycho.nsa.gov> Date: Fri, 9 Sep 2005 13:01:41 -0700 Subject: [PATCH 078/563] [PATCH] ext3: Enable atomic inode security labeling This patch modifies ext3 to call the inode_init_security LSM hook to obtain the security attribute for a newly created inode and to set the resulting attribute on the new inode as part of the same transaction. This parallels the existing processing for setting ACLs on newly created inodes. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/ext3/ialloc.c | 5 +++++ fs/ext3/xattr.h | 11 +++++++++++ fs/ext3/xattr_security.c | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 6981bd014ede9..96552769d039e 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -607,6 +607,11 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) DQUOT_DROP(inode); goto fail2; } + err = ext3_init_security(handle,inode, dir); + if (err) { + DQUOT_FREE_INODE(inode); + goto fail2; + } err = ext3_mark_inode_dirty(handle, inode); if (err) { ext3_std_error(sb, err); diff --git a/fs/ext3/xattr.h b/fs/ext3/xattr.h index eb31a69e82dc9..2ceae38f3d497 100644 --- a/fs/ext3/xattr.h +++ b/fs/ext3/xattr.h @@ -133,3 +133,14 @@ exit_ext3_xattr(void) #define ext3_xattr_handlers NULL # endif /* CONFIG_EXT3_FS_XATTR */ + +#ifdef CONFIG_EXT3_FS_SECURITY +extern int ext3_init_security(handle_t *handle, struct inode *inode, + struct inode *dir); +#else +static inline int ext3_init_security(handle_t *handle, struct inode *inode, + struct inode *dir) +{ + return 0; +} +#endif diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c index ddc1c41750e14..b9c40c15647bb 100644 --- a/fs/ext3/xattr_security.c +++ b/fs/ext3/xattr_security.c @@ -9,6 +9,7 @@ #include <linux/smp_lock.h> #include <linux/ext3_jbd.h> #include <linux/ext3_fs.h> +#include <linux/security.h> #include "xattr.h" static size_t @@ -47,6 +48,27 @@ ext3_xattr_security_set(struct inode *inode, const char *name, value, size, flags); } +int +ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir) +{ + int err; + size_t len; + void *value; + char *name; + + err = security_inode_init_security(inode, dir, &name, &value, &len); + if (err) { + if (err == -EOPNOTSUPP) + return 0; + return err; + } + err = ext3_xattr_set_handle(handle, inode, EXT3_XATTR_INDEX_SECURITY, + name, value, len, 0); + kfree(name); + kfree(value); + return err; +} + struct xattr_handler ext3_xattr_security_handler = { .prefix = XATTR_SECURITY_PREFIX, .list = ext3_xattr_security_list, -- GitLab From 570bc1c2e5ccdb408081e77507a385dc7ebed7fa Mon Sep 17 00:00:00 2001 From: Stephen Smalley <sds@tycho.nsa.gov> Date: Fri, 9 Sep 2005 13:01:43 -0700 Subject: [PATCH 079/563] [PATCH] tmpfs: Enable atomic inode security labeling This patch modifies tmpfs to call the inode_init_security LSM hook to set up the incore inode security state for new inodes before the inode becomes accessible via the dcache. As there is no underlying storage of security xattrs in this case, it is not necessary for the hook to return the (name, value, len) triple to the tmpfs code, so this patch also modifies the SELinux hook function to correctly handle the case where the (name, value, len) pointers are NULL. The hook call is needed in tmpfs in order to support proper security labeling of tmpfs inodes (e.g. for udev with tmpfs /dev in Fedora). With this change in place, we should then be able to remove the security_inode_post_create/mkdir/... hooks safely. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Cc: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- mm/shmem.c | 20 +++++++++++++++++++- security/selinux/hooks.c | 27 ++++++++++++++++----------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index 0d627a37da954..1f7aeb210c7bf 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1608,6 +1608,15 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) int error = -ENOSPC; if (inode) { + error = security_inode_init_security(inode, dir, NULL, NULL, + NULL); + if (error) { + if (error != -EOPNOTSUPP) { + iput(inode); + return error; + } + error = 0; + } if (dir->i_mode & S_ISGID) { inode->i_gid = dir->i_gid; if (S_ISDIR(mode)) @@ -1617,7 +1626,6 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) dir->i_ctime = dir->i_mtime = CURRENT_TIME; d_instantiate(dentry, inode); dget(dentry); /* Extra count - pin the dentry in core */ - error = 0; } return error; } @@ -1747,6 +1755,16 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s if (!inode) return -ENOSPC; + error = security_inode_init_security(inode, dir, NULL, NULL, + NULL); + if (error) { + if (error != -EOPNOTSUPP) { + iput(inode); + return error; + } + error = 0; + } + info = SHMEM_I(inode); inode->i_size = len-1; if (len <= (char *)inode - (char *)info) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 63701fe0e1ad6..265f33d3af9b1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2032,9 +2032,9 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; struct inode_security_struct *isec; - u32 newsid; + u32 newsid, clen; int rc; - char *namep, *context; + char *namep = NULL, *context; tsec = current->security; dsec = dir->i_security; @@ -2059,17 +2059,22 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, inode_security_set_sid(inode, newsid); - namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL); - if (!namep) - return -ENOMEM; - *name = namep; + if (name) { + namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL); + if (!namep) + return -ENOMEM; + *name = namep; + } - rc = security_sid_to_context(newsid, &context, len); - if (rc) { - kfree(namep); - return rc; + if (value && len) { + rc = security_sid_to_context(newsid, &context, &clen); + if (rc) { + kfree(namep); + return rc; + } + *value = context; + *len = clen; } - *value = context; isec->security_attr_init = 1; -- GitLab From a74574aafea3a63add3251047601611111f44562 Mon Sep 17 00:00:00 2001 From: Stephen Smalley <sds@tycho.nsa.gov> Date: Fri, 9 Sep 2005 13:01:44 -0700 Subject: [PATCH 080/563] [PATCH] Remove security_inode_post_create/mkdir/symlink/mknod hooks This patch removes the inode_post_create/mkdir/mknod/symlink LSM hooks as they are obsoleted by the new inode_init_security hook that enables atomic inode security labeling. If anyone sees any reason to retain these hooks, please speak now. Also, is anyone using the post_rename/link hooks; if not, those could also be removed. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/namei.c | 16 ++--- include/linux/security.h | 90 ------------------------ security/dummy.c | 28 -------- security/selinux/hooks.c | 111 ------------------------------ security/selinux/include/objsec.h | 1 - 5 files changed, 4 insertions(+), 242 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 145e852c4bd02..993a65a7d5707 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1316,10 +1316,8 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode, return error; DQUOT_INIT(dir); error = dir->i_op->create(dir, dentry, mode, nd); - if (!error) { + if (!error) fsnotify_create(dir, dentry->d_name.name); - security_inode_post_create(dir, dentry, mode); - } return error; } @@ -1635,10 +1633,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) DQUOT_INIT(dir); error = dir->i_op->mknod(dir, dentry, mode, dev); - if (!error) { + if (!error) fsnotify_create(dir, dentry->d_name.name); - security_inode_post_mknod(dir, dentry, mode, dev); - } return error; } @@ -1708,10 +1704,8 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) DQUOT_INIT(dir); error = dir->i_op->mkdir(dir, dentry, mode); - if (!error) { + if (!error) fsnotify_mkdir(dir, dentry->d_name.name); - security_inode_post_mkdir(dir,dentry, mode); - } return error; } @@ -1947,10 +1941,8 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i DQUOT_INIT(dir); error = dir->i_op->symlink(dir, dentry, oldname); - if (!error) { + if (!error) fsnotify_create(dir, dentry->d_name.name); - security_inode_post_symlink(dir, dentry, oldname); - } return error; } diff --git a/include/linux/security.h b/include/linux/security.h index d4f3b7a94ea6e..875225bf8986e 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -275,12 +275,6 @@ struct swap_info_struct; * @dentry contains the dentry structure for the file to be created. * @mode contains the file mode of the file to be created. * Return 0 if permission is granted. - * @inode_post_create: - * Set the security attributes on a newly created regular file. This hook - * is called after a file has been successfully created. - * @dir contains the inode structure of the parent directory of the new file. - * @dentry contains the the dentry structure for the newly created file. - * @mode contains the file mode. * @inode_link: * Check permission before creating a new hard link to a file. * @old_dentry contains the dentry structure for an existing link to the file. @@ -303,13 +297,6 @@ struct swap_info_struct; * @dentry contains the dentry structure of the symbolic link. * @old_name contains the pathname of file. * Return 0 if permission is granted. - * @inode_post_symlink: - * @dir contains the inode structure of the parent directory of the new link. - * @dentry contains the dentry structure of new symbolic link. - * @old_name contains the pathname of file. - * Set security attributes for a newly created symbolic link. Note that - * @dentry->d_inode may be NULL, since the filesystem might not - * instantiate the dentry (e.g. NFS). * @inode_mkdir: * Check permissions to create a new directory in the existing directory * associated with inode strcture @dir. @@ -317,11 +304,6 @@ struct swap_info_struct; * @dentry contains the dentry structure of new directory. * @mode contains the mode of new directory. * Return 0 if permission is granted. - * @inode_post_mkdir: - * Set security attributes on a newly created directory. - * @dir contains the inode structure of parent of the directory to be created. - * @dentry contains the dentry structure of new directory. - * @mode contains the mode of new directory. * @inode_rmdir: * Check the permission to remove a directory. * @dir contains the inode structure of parent of the directory to be removed. @@ -337,13 +319,6 @@ struct swap_info_struct; * @mode contains the mode of the new file. * @dev contains the the device number. * Return 0 if permission is granted. - * @inode_post_mknod: - * Set security attributes on a newly created special file (or socket or - * fifo file created via the mknod system call). - * @dir contains the inode structure of parent of the new node. - * @dentry contains the dentry structure of the new node. - * @mode contains the mode of the new node. - * @dev contains the the device number. * @inode_rename: * Check for permission to rename a file or directory. * @old_dir contains the inode structure for parent of the old link. @@ -1103,8 +1078,6 @@ struct security_operations { char **name, void **value, size_t *len); int (*inode_create) (struct inode *dir, struct dentry *dentry, int mode); - void (*inode_post_create) (struct inode *dir, - struct dentry *dentry, int mode); int (*inode_link) (struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry); void (*inode_post_link) (struct dentry *old_dentry, @@ -1112,17 +1085,10 @@ struct security_operations { int (*inode_unlink) (struct inode *dir, struct dentry *dentry); int (*inode_symlink) (struct inode *dir, struct dentry *dentry, const char *old_name); - void (*inode_post_symlink) (struct inode *dir, - struct dentry *dentry, - const char *old_name); int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, int mode); - void (*inode_post_mkdir) (struct inode *dir, struct dentry *dentry, - int mode); int (*inode_rmdir) (struct inode *dir, struct dentry *dentry); int (*inode_mknod) (struct inode *dir, struct dentry *dentry, int mode, dev_t dev); - void (*inode_post_mknod) (struct inode *dir, struct dentry *dentry, - int mode, dev_t dev); int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry); void (*inode_post_rename) (struct inode *old_dir, @@ -1484,15 +1450,6 @@ static inline int security_inode_create (struct inode *dir, return security_ops->inode_create (dir, dentry, mode); } -static inline void security_inode_post_create (struct inode *dir, - struct dentry *dentry, - int mode) -{ - if (dentry->d_inode && unlikely (IS_PRIVATE (dentry->d_inode))) - return; - security_ops->inode_post_create (dir, dentry, mode); -} - static inline int security_inode_link (struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) @@ -1528,15 +1485,6 @@ static inline int security_inode_symlink (struct inode *dir, return security_ops->inode_symlink (dir, dentry, old_name); } -static inline void security_inode_post_symlink (struct inode *dir, - struct dentry *dentry, - const char *old_name) -{ - if (dentry->d_inode && unlikely (IS_PRIVATE (dentry->d_inode))) - return; - security_ops->inode_post_symlink (dir, dentry, old_name); -} - static inline int security_inode_mkdir (struct inode *dir, struct dentry *dentry, int mode) @@ -1546,15 +1494,6 @@ static inline int security_inode_mkdir (struct inode *dir, return security_ops->inode_mkdir (dir, dentry, mode); } -static inline void security_inode_post_mkdir (struct inode *dir, - struct dentry *dentry, - int mode) -{ - if (dentry->d_inode && unlikely (IS_PRIVATE (dentry->d_inode))) - return; - security_ops->inode_post_mkdir (dir, dentry, mode); -} - static inline int security_inode_rmdir (struct inode *dir, struct dentry *dentry) { @@ -1572,15 +1511,6 @@ static inline int security_inode_mknod (struct inode *dir, return security_ops->inode_mknod (dir, dentry, mode, dev); } -static inline void security_inode_post_mknod (struct inode *dir, - struct dentry *dentry, - int mode, dev_t dev) -{ - if (dentry->d_inode && unlikely (IS_PRIVATE (dentry->d_inode))) - return; - security_ops->inode_post_mknod (dir, dentry, mode, dev); -} - static inline int security_inode_rename (struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, @@ -2220,11 +2150,6 @@ static inline int security_inode_create (struct inode *dir, return 0; } -static inline void security_inode_post_create (struct inode *dir, - struct dentry *dentry, - int mode) -{ } - static inline int security_inode_link (struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) @@ -2250,11 +2175,6 @@ static inline int security_inode_symlink (struct inode *dir, return 0; } -static inline void security_inode_post_symlink (struct inode *dir, - struct dentry *dentry, - const char *old_name) -{ } - static inline int security_inode_mkdir (struct inode *dir, struct dentry *dentry, int mode) @@ -2262,11 +2182,6 @@ static inline int security_inode_mkdir (struct inode *dir, return 0; } -static inline void security_inode_post_mkdir (struct inode *dir, - struct dentry *dentry, - int mode) -{ } - static inline int security_inode_rmdir (struct inode *dir, struct dentry *dentry) { @@ -2280,11 +2195,6 @@ static inline int security_inode_mknod (struct inode *dir, return 0; } -static inline void security_inode_post_mknod (struct inode *dir, - struct dentry *dentry, - int mode, dev_t dev) -{ } - static inline int security_inode_rename (struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, diff --git a/security/dummy.c b/security/dummy.c index e8a00fa804699..5083314e14b1d 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -270,12 +270,6 @@ static int dummy_inode_create (struct inode *inode, struct dentry *dentry, return 0; } -static void dummy_inode_post_create (struct inode *inode, struct dentry *dentry, - int mask) -{ - return; -} - static int dummy_inode_link (struct dentry *old_dentry, struct inode *inode, struct dentry *new_dentry) { @@ -300,24 +294,12 @@ static int dummy_inode_symlink (struct inode *inode, struct dentry *dentry, return 0; } -static void dummy_inode_post_symlink (struct inode *inode, - struct dentry *dentry, const char *name) -{ - return; -} - static int dummy_inode_mkdir (struct inode *inode, struct dentry *dentry, int mask) { return 0; } -static void dummy_inode_post_mkdir (struct inode *inode, struct dentry *dentry, - int mask) -{ - return; -} - static int dummy_inode_rmdir (struct inode *inode, struct dentry *dentry) { return 0; @@ -329,12 +311,6 @@ static int dummy_inode_mknod (struct inode *inode, struct dentry *dentry, return 0; } -static void dummy_inode_post_mknod (struct inode *inode, struct dentry *dentry, - int mode, dev_t dev) -{ - return; -} - static int dummy_inode_rename (struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, @@ -894,17 +870,13 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, inode_free_security); set_to_dummy_if_null(ops, inode_init_security); set_to_dummy_if_null(ops, inode_create); - set_to_dummy_if_null(ops, inode_post_create); set_to_dummy_if_null(ops, inode_link); set_to_dummy_if_null(ops, inode_post_link); set_to_dummy_if_null(ops, inode_unlink); set_to_dummy_if_null(ops, inode_symlink); - set_to_dummy_if_null(ops, inode_post_symlink); set_to_dummy_if_null(ops, inode_mkdir); - set_to_dummy_if_null(ops, inode_post_mkdir); set_to_dummy_if_null(ops, inode_rmdir); set_to_dummy_if_null(ops, inode_mknod); - set_to_dummy_if_null(ops, inode_post_mknod); set_to_dummy_if_null(ops, inode_rename); set_to_dummy_if_null(ops, inode_post_rename); set_to_dummy_if_null(ops, inode_readlink); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 265f33d3af9b1..c9c20828be798 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1265,91 +1265,6 @@ static int inode_security_set_sid(struct inode *inode, u32 sid) return 0; } -/* Set the security attributes on a newly created file. */ -static int post_create(struct inode *dir, - struct dentry *dentry) -{ - - struct task_security_struct *tsec; - struct inode *inode; - struct inode_security_struct *dsec; - struct superblock_security_struct *sbsec; - struct inode_security_struct *isec; - u32 newsid; - char *context; - unsigned int len; - int rc; - - tsec = current->security; - dsec = dir->i_security; - sbsec = dir->i_sb->s_security; - - inode = dentry->d_inode; - if (!inode) { - /* Some file system types (e.g. NFS) may not instantiate - a dentry for all create operations (e.g. symlink), - so we have to check to see if the inode is non-NULL. */ - printk(KERN_WARNING "post_create: no inode, dir (dev=%s, " - "ino=%ld)\n", dir->i_sb->s_id, dir->i_ino); - return 0; - } - - isec = inode->i_security; - - if (isec->security_attr_init) - return 0; - - if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { - newsid = tsec->create_sid; - } else { - rc = security_transition_sid(tsec->sid, dsec->sid, - inode_mode_to_security_class(inode->i_mode), - &newsid); - if (rc) { - printk(KERN_WARNING "post_create: " - "security_transition_sid failed, rc=%d (dev=%s " - "ino=%ld)\n", - -rc, inode->i_sb->s_id, inode->i_ino); - return rc; - } - } - - rc = inode_security_set_sid(inode, newsid); - if (rc) { - printk(KERN_WARNING "post_create: inode_security_set_sid " - "failed, rc=%d (dev=%s ino=%ld)\n", - -rc, inode->i_sb->s_id, inode->i_ino); - return rc; - } - - if (sbsec->behavior == SECURITY_FS_USE_XATTR && - inode->i_op->setxattr) { - /* Use extended attributes. */ - rc = security_sid_to_context(newsid, &context, &len); - if (rc) { - printk(KERN_WARNING "post_create: sid_to_context " - "failed, rc=%d (dev=%s ino=%ld)\n", - -rc, inode->i_sb->s_id, inode->i_ino); - return rc; - } - down(&inode->i_sem); - rc = inode->i_op->setxattr(dentry, - XATTR_NAME_SELINUX, - context, len, 0); - up(&inode->i_sem); - kfree(context); - if (rc < 0) { - printk(KERN_WARNING "post_create: setxattr failed, " - "rc=%d (dev=%s ino=%ld)\n", - -rc, inode->i_sb->s_id, inode->i_ino); - return rc; - } - } - - return 0; -} - - /* Hook functions begin here. */ static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) @@ -2076,8 +1991,6 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, *len = clen; } - isec->security_attr_init = 1; - return 0; } @@ -2086,11 +1999,6 @@ static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int ma return may_create(dir, dentry, SECCLASS_FILE); } -static void selinux_inode_post_create(struct inode *dir, struct dentry *dentry, int mask) -{ - post_create(dir, dentry); -} - static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { int rc; @@ -2121,21 +2029,11 @@ static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const return may_create(dir, dentry, SECCLASS_LNK_FILE); } -static void selinux_inode_post_symlink(struct inode *dir, struct dentry *dentry, const char *name) -{ - post_create(dir, dentry); -} - static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask) { return may_create(dir, dentry, SECCLASS_DIR); } -static void selinux_inode_post_mkdir(struct inode *dir, struct dentry *dentry, int mask) -{ - post_create(dir, dentry); -} - static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry) { return may_link(dir, dentry, MAY_RMDIR); @@ -2152,11 +2050,6 @@ static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mod return may_create(dir, dentry, inode_mode_to_security_class(mode)); } -static void selinux_inode_post_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) -{ - post_create(dir, dentry); -} - static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, struct dentry *new_dentry) { @@ -4363,17 +4256,13 @@ static struct security_operations selinux_ops = { .inode_free_security = selinux_inode_free_security, .inode_init_security = selinux_inode_init_security, .inode_create = selinux_inode_create, - .inode_post_create = selinux_inode_post_create, .inode_link = selinux_inode_link, .inode_post_link = selinux_inode_post_link, .inode_unlink = selinux_inode_unlink, .inode_symlink = selinux_inode_symlink, - .inode_post_symlink = selinux_inode_post_symlink, .inode_mkdir = selinux_inode_mkdir, - .inode_post_mkdir = selinux_inode_post_mkdir, .inode_rmdir = selinux_inode_rmdir, .inode_mknod = selinux_inode_mknod, - .inode_post_mknod = selinux_inode_post_mknod, .inode_rename = selinux_inode_rename, .inode_post_rename = selinux_inode_post_rename, .inode_readlink = selinux_inode_readlink, diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index c515bc0b58a1a..887937c8134a4 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -46,7 +46,6 @@ struct inode_security_struct { unsigned char initialized; /* initialization flag */ struct semaphore sem; unsigned char inherit; /* inherit SID from parent entry */ - unsigned char security_attr_init; /* security attributes init flag */ }; struct file_security_struct { -- GitLab From e31e14ec356f36b131576be5bc31d8fef7e95483 Mon Sep 17 00:00:00 2001 From: Stephen Smalley <sds@tycho.nsa.gov> Date: Fri, 9 Sep 2005 13:01:45 -0700 Subject: [PATCH 081/563] [PATCH] remove the inode_post_link and inode_post_rename LSM hooks This patch removes the inode_post_link and inode_post_rename LSM hooks as they are unused (and likely useless). Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/namei.c | 10 ++------ include/linux/security.h | 49 ---------------------------------------- security/dummy.c | 17 -------------- security/selinux/hooks.c | 13 ----------- 4 files changed, 2 insertions(+), 87 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 993a65a7d5707..21d85f1ac8395 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2012,10 +2012,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de DQUOT_INIT(dir); error = dir->i_op->link(old_dentry, dir, new_dentry); up(&old_dentry->d_inode->i_sem); - if (!error) { + if (!error) fsnotify_create(dir, new_dentry->d_name.name); - security_inode_post_link(old_dentry, dir, new_dentry); - } return error; } @@ -2134,11 +2132,8 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, d_rehash(new_dentry); dput(new_dentry); } - if (!error) { + if (!error) d_move(old_dentry,new_dentry); - security_inode_post_rename(old_dir, old_dentry, - new_dir, new_dentry); - } return error; } @@ -2164,7 +2159,6 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, /* The following d_move() should become unconditional */ if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) d_move(old_dentry, new_dentry); - security_inode_post_rename(old_dir, old_dentry, new_dir, new_dentry); } if (target) up(&target->i_sem); diff --git a/include/linux/security.h b/include/linux/security.h index 875225bf8986e..55b02e1c73f41 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -281,11 +281,6 @@ struct swap_info_struct; * @dir contains the inode structure of the parent directory of the new link. * @new_dentry contains the dentry structure for the new link. * Return 0 if permission is granted. - * @inode_post_link: - * Set security attributes for a new hard link to a file. - * @old_dentry contains the dentry structure for the existing link. - * @dir contains the inode structure of the parent directory of the new file. - * @new_dentry contains the dentry structure for the new file link. * @inode_unlink: * Check the permission to remove a hard link to a file. * @dir contains the inode structure of parent directory of the file. @@ -326,12 +321,6 @@ struct swap_info_struct; * @new_dir contains the inode structure for parent of the new link. * @new_dentry contains the dentry structure of the new link. * Return 0 if permission is granted. - * @inode_post_rename: - * Set security attributes on a renamed file or directory. - * @old_dir contains the inode structure for parent of the old link. - * @old_dentry contains the dentry structure of the old link. - * @new_dir contains the inode structure for parent of the new link. - * @new_dentry contains the dentry structure of the new link. * @inode_readlink: * Check the permission to read the symbolic link. * @dentry contains the dentry structure for the file link. @@ -1080,8 +1069,6 @@ struct security_operations { struct dentry *dentry, int mode); int (*inode_link) (struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry); - void (*inode_post_link) (struct dentry *old_dentry, - struct inode *dir, struct dentry *new_dentry); int (*inode_unlink) (struct inode *dir, struct dentry *dentry); int (*inode_symlink) (struct inode *dir, struct dentry *dentry, const char *old_name); @@ -1091,10 +1078,6 @@ struct security_operations { int mode, dev_t dev); int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry); - void (*inode_post_rename) (struct inode *old_dir, - struct dentry *old_dentry, - struct inode *new_dir, - struct dentry *new_dentry); int (*inode_readlink) (struct dentry *dentry); int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd); int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd); @@ -1459,15 +1442,6 @@ static inline int security_inode_link (struct dentry *old_dentry, return security_ops->inode_link (old_dentry, dir, new_dentry); } -static inline void security_inode_post_link (struct dentry *old_dentry, - struct inode *dir, - struct dentry *new_dentry) -{ - if (new_dentry->d_inode && unlikely (IS_PRIVATE (new_dentry->d_inode))) - return; - security_ops->inode_post_link (old_dentry, dir, new_dentry); -} - static inline int security_inode_unlink (struct inode *dir, struct dentry *dentry) { @@ -1523,18 +1497,6 @@ static inline int security_inode_rename (struct inode *old_dir, new_dir, new_dentry); } -static inline void security_inode_post_rename (struct inode *old_dir, - struct dentry *old_dentry, - struct inode *new_dir, - struct dentry *new_dentry) -{ - if (unlikely (IS_PRIVATE (old_dentry->d_inode) || - (new_dentry->d_inode && IS_PRIVATE (new_dentry->d_inode)))) - return; - security_ops->inode_post_rename (old_dir, old_dentry, - new_dir, new_dentry); -} - static inline int security_inode_readlink (struct dentry *dentry) { if (unlikely (IS_PRIVATE (dentry->d_inode))) @@ -2157,11 +2119,6 @@ static inline int security_inode_link (struct dentry *old_dentry, return 0; } -static inline void security_inode_post_link (struct dentry *old_dentry, - struct inode *dir, - struct dentry *new_dentry) -{ } - static inline int security_inode_unlink (struct inode *dir, struct dentry *dentry) { @@ -2203,12 +2160,6 @@ static inline int security_inode_rename (struct inode *old_dir, return 0; } -static inline void security_inode_post_rename (struct inode *old_dir, - struct dentry *old_dentry, - struct inode *new_dir, - struct dentry *new_dentry) -{ } - static inline int security_inode_readlink (struct dentry *dentry) { return 0; diff --git a/security/dummy.c b/security/dummy.c index 5083314e14b1d..9623a61dfc763 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -276,13 +276,6 @@ static int dummy_inode_link (struct dentry *old_dentry, struct inode *inode, return 0; } -static void dummy_inode_post_link (struct dentry *old_dentry, - struct inode *inode, - struct dentry *new_dentry) -{ - return; -} - static int dummy_inode_unlink (struct inode *inode, struct dentry *dentry) { return 0; @@ -319,14 +312,6 @@ static int dummy_inode_rename (struct inode *old_inode, return 0; } -static void dummy_inode_post_rename (struct inode *old_inode, - struct dentry *old_dentry, - struct inode *new_inode, - struct dentry *new_dentry) -{ - return; -} - static int dummy_inode_readlink (struct dentry *dentry) { return 0; @@ -871,14 +856,12 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, inode_init_security); set_to_dummy_if_null(ops, inode_create); set_to_dummy_if_null(ops, inode_link); - set_to_dummy_if_null(ops, inode_post_link); set_to_dummy_if_null(ops, inode_unlink); set_to_dummy_if_null(ops, inode_symlink); set_to_dummy_if_null(ops, inode_mkdir); set_to_dummy_if_null(ops, inode_rmdir); set_to_dummy_if_null(ops, inode_mknod); set_to_dummy_if_null(ops, inode_rename); - set_to_dummy_if_null(ops, inode_post_rename); set_to_dummy_if_null(ops, inode_readlink); set_to_dummy_if_null(ops, inode_follow_link); set_to_dummy_if_null(ops, inode_permission); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c9c20828be798..3f0b533be92c7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2009,11 +2009,6 @@ static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, stru return may_link(dir, old_dentry, MAY_LINK); } -static void selinux_inode_post_link(struct dentry *old_dentry, struct inode *inode, struct dentry *new_dentry) -{ - return; -} - static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry) { int rc; @@ -2056,12 +2051,6 @@ static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dent return may_rename(old_inode, old_dentry, new_inode, new_dentry); } -static void selinux_inode_post_rename(struct inode *old_inode, struct dentry *old_dentry, - struct inode *new_inode, struct dentry *new_dentry) -{ - return; -} - static int selinux_inode_readlink(struct dentry *dentry) { return dentry_has_perm(current, NULL, dentry, FILE__READ); @@ -4257,14 +4246,12 @@ static struct security_operations selinux_ops = { .inode_init_security = selinux_inode_init_security, .inode_create = selinux_inode_create, .inode_link = selinux_inode_link, - .inode_post_link = selinux_inode_post_link, .inode_unlink = selinux_inode_unlink, .inode_symlink = selinux_inode_symlink, .inode_mkdir = selinux_inode_mkdir, .inode_rmdir = selinux_inode_rmdir, .inode_mknod = selinux_inode_mknod, .inode_rename = selinux_inode_rename, - .inode_post_rename = selinux_inode_post_rename, .inode_readlink = selinux_inode_readlink, .inode_follow_link = selinux_inode_follow_link, .inode_permission = selinux_inode_permission, -- GitLab From 83f7da8acd81354e921ff12d6efbeae5b1a5d6a4 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti <marcelo.tosatti@cyclades.com> Date: Fri, 9 Sep 2005 13:01:45 -0700 Subject: [PATCH 082/563] [PATCH] ppc32: make perfmon.o CONFIG_E500 specific Subject says it all, there is no need to link perfmon.o on sub-architectures other than CONFIG_E500. Signed-off-by: Marcelo Tosatti <marcelo.tosatti@cyclades.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ppc/kernel/Makefile | 3 ++- arch/ppc/kernel/traps.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index b1457a8a9c0f0..1fb92f16acd61 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -15,8 +15,9 @@ extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o signal.o ptrace.o align.o \ semaphore.o syscalls.o setup.o \ - cputable.o ppc_htab.o perfmon.o + cputable.o ppc_htab.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o +obj-$(CONFIG_E500) += perfmon.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_POWER4) += cpu_setup_power4.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index d87423d1003a6..8356d544fa60d 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -849,10 +849,12 @@ void AltivecAssistException(struct pt_regs *regs) } #endif /* CONFIG_ALTIVEC */ +#ifdef CONFIG_E500 void PerformanceMonitorException(struct pt_regs *regs) { perf_irq(regs); } +#endif #ifdef CONFIG_FSL_BOOKE void CacheLockingException(struct pt_regs *regs, unsigned long address, -- GitLab From 99cc2192132ab28c495d015ed2e95dc29e2a27ad Mon Sep 17 00:00:00 2001 From: Frank van Maarseveen <frankvm@frankvm.com> Date: Fri, 9 Sep 2005 13:01:46 -0700 Subject: [PATCH 083/563] [PATCH] ppc32: Correct an instruction in the boot code In the flush and invalidate bootcode on PPC4xx we were accidentally using the wrong instruction. Use cmplw, which reads from a register like we want. Signed-off-by: Tom Rini <trini@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ppc/boot/common/util.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S index 47e641455bc59..c96c9f80521ec 100644 --- a/arch/ppc/boot/common/util.S +++ b/arch/ppc/boot/common/util.S @@ -252,7 +252,7 @@ _GLOBAL(flush_instruction_cache) 1: dcbf r0,r3 # Flush the data cache icbi r0,r3 # Invalidate the instruction cache addi r3,r3,0x10 # Increment by one cache line - cmplwi cr0,r3,r4 # Are we at the end yet? + cmplw cr0,r3,r4 # Are we at the end yet? blt 1b # No, keep flushing and invalidating #else /* Enable, invalidate and then disable the L1 icache/dcache. */ -- GitLab From 66b375bf7d9c995fd6169191c3862071e710f456 Mon Sep 17 00:00:00 2001 From: Tom Rini <trini@kernel.crashing.org> Date: Fri, 9 Sep 2005 13:01:47 -0700 Subject: [PATCH 084/563] [PATCH] ppc32: In the boot code, don't rely on BASE_BAUD directly Modifies serial_init to get base baud rate from the rs_table entry instead of BAUD_BASE. This patch eliminates duplication between the SERIAL_PORT_DFNS macro and BAUD_BASE. Without the patch, if a port set the baud rate in SERIAL_PORT_DFNS, but did not update BASE_BAUD, the BASE_BAUD value would still be used. Signed-off-by: Grant Likely <grant.likely@gdcanada.com> Signed-off-by: Tom Rini <trini@kernel.crashing.org> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ppc/boot/common/ns16550.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/ppc/boot/common/ns16550.c b/arch/ppc/boot/common/ns16550.c index 9017c547a6f6f..26818bbb6cfff 100644 --- a/arch/ppc/boot/common/ns16550.c +++ b/arch/ppc/boot/common/ns16550.c @@ -23,7 +23,7 @@ static int shift; unsigned long serial_init(int chan, void *ignored) { - unsigned long com_port; + unsigned long com_port, base_baud; unsigned char lcr, dlm; /* We need to find out which type io we're expecting. If it's @@ -43,6 +43,8 @@ unsigned long serial_init(int chan, void *ignored) /* How far apart the registers are. */ shift = rs_table[chan].iomem_reg_shift; + /* Base baud.. */ + base_baud = rs_table[chan].baud_base; /* save the LCR */ lcr = inb(com_port + (UART_LCR << shift)); @@ -62,9 +64,9 @@ unsigned long serial_init(int chan, void *ignored) else { /* Input clock. */ outb(com_port + (UART_DLL << shift), - (BASE_BAUD / SERIAL_BAUD) & 0xFF); + (base_baud / SERIAL_BAUD) & 0xFF); outb(com_port + (UART_DLM << shift), - (BASE_BAUD / SERIAL_BAUD) >> 8); + (base_baud / SERIAL_BAUD) >> 8); /* 8 data, 1 stop, no parity */ outb(com_port + (UART_LCR << shift), 0x03); /* RTS/DTR */ -- GitLab From 95409aaca734700e8dcba9db685b8600b67ba05d Mon Sep 17 00:00:00 2001 From: Tom Rini <trini@kernel.crashing.org> Date: Fri, 9 Sep 2005 13:01:48 -0700 Subject: [PATCH 085/563] [PATCH] ppc32: Kill PVR_440* defines The following patch changes the usages of PVR_440* into strcmp's with the cpu_name field, and removes the defines altogether. The Ebony portion was briefly tested long ago. One benefit of moving from PVR-tests to string tests in general is that not all CPUs can be on and be able to do this type of comparison. See http://patchwork.ozlabs.org/linuxppc/patch?id=1250 for the original thread. Signed-off-by: Tom Rini <trini@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ppc/platforms/4xx/ebony.c | 13 ++++--------- arch/ppc/syslib/ibm440gx_common.c | 7 ++++--- include/asm-ppc/reg.h | 6 ------ 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c index 0fd3442f51310..d6b2b1965dcb3 100644 --- a/arch/ppc/platforms/4xx/ebony.c +++ b/arch/ppc/platforms/4xx/ebony.c @@ -91,15 +91,10 @@ ebony_calibrate_decr(void) * on Rev. C silicon then errata forces us to * use the internal clock. */ - switch (PVR_REV(mfspr(SPRN_PVR))) { - case PVR_REV(PVR_440GP_RB): - freq = EBONY_440GP_RB_SYSCLK; - break; - case PVR_REV(PVR_440GP_RC1): - default: - freq = EBONY_440GP_RC_SYSCLK; - break; - } + if (strcmp(cur_cpu_spec[0]->cpu_name, "440GP Rev. B") == 0) + freq = EBONY_440GP_RB_SYSCLK; + else + freq = EBONY_440GP_RC_SYSCLK; ibm44x_calibrate_decr(freq); } diff --git a/arch/ppc/syslib/ibm440gx_common.c b/arch/ppc/syslib/ibm440gx_common.c index d4776af6a3ca2..0bb919859b8be 100644 --- a/arch/ppc/syslib/ibm440gx_common.c +++ b/arch/ppc/syslib/ibm440gx_common.c @@ -236,9 +236,10 @@ void __init ibm440gx_l2c_setup(struct ibm44x_clocks* p) /* Disable L2C on rev.A, rev.B and 800MHz version of rev.C, enable it on all other revisions */ - u32 pvr = mfspr(SPRN_PVR); - if (pvr == PVR_440GX_RA || pvr == PVR_440GX_RB || - (pvr == PVR_440GX_RC && p->cpu > 667000000)) + if (strcmp(cur_cpu_spec[0]->cpu_name, "440GX Rev. A") == 0 || + strcmp(cur_cpu_spec[0]->cpu_name, "440GX Rev. B") == 0 + || (strcmp(cur_cpu_spec[0]->cpu_name, "440GX Rev. C") + == 0 && p->cpu > 667000000)) ibm440gx_l2c_disable(); else ibm440gx_l2c_enable(); diff --git a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h index 88b4222154d48..73c33e3ef9c6d 100644 --- a/include/asm-ppc/reg.h +++ b/include/asm-ppc/reg.h @@ -366,12 +366,6 @@ #define PVR_STB03XXX 0x40310000 #define PVR_NP405H 0x41410000 #define PVR_NP405L 0x41610000 -#define PVR_440GP_RB 0x40120440 -#define PVR_440GP_RC1 0x40120481 -#define PVR_440GP_RC2 0x40200481 -#define PVR_440GX_RA 0x51b21850 -#define PVR_440GX_RB 0x51b21851 -#define PVR_440GX_RC 0x51b21892 #define PVR_601 0x00010000 #define PVR_602 0x00050000 #define PVR_603 0x00030000 -- GitLab From 4d666d7ada2e14d71d463c85b8b5ef2e2e6723f2 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa <yuasa@hh.iij4u.or.jp> Date: Fri, 9 Sep 2005 13:01:49 -0700 Subject: [PATCH 086/563] [PATCH] mips: add TANBAC TB0287 support Add TANBAC TB0287 support. Signed-off-by: Yoichi Yuasa <yuasa@hh.iij4u.or.jp> Cc: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/mips/Kconfig | 7 + arch/mips/configs/tb0287_defconfig | 1041 ++++++++++++++++++++++++++++ arch/mips/pci/Makefile | 1 + arch/mips/pci/fixup-tb0287.c | 65 ++ include/asm-mips/vr41xx/tb0287.h | 43 ++ 5 files changed, 1157 insertions(+) create mode 100644 arch/mips/configs/tb0287_defconfig create mode 100644 arch/mips/pci/fixup-tb0287.c create mode 100644 include/asm-mips/vr41xx/tb0287.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8d76eb1ff2916..0eb71ac303af2 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -154,6 +154,13 @@ config TANBAC_TB0226 The TANBAC Mbase(TB0226) is a MIPS-based platform manufactured by TANBAC. Please refer to <http://www.tanbac.co.jp/> about Mbase. +config TANBAC_TB0287 + bool "Support for TANBAC Mini-ITX DIMM base(TB0287)" + depends on TANBAC_TB022X + help + The TANBAC Mini-ITX DIMM base(TB0287) is a MIPS-based platform manufactured by TANBAC. + Please refer to <http://www.tanbac.co.jp/> about Mini-ITX DIMM base. + config VICTOR_MPC30X bool "Support for Victor MP-C303/304" depends on MACH_VR41XX diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig new file mode 100644 index 0000000000000..17b9f2f65ba0a --- /dev/null +++ b/arch/mips/configs/tb0287_defconfig @@ -0,0 +1,1041 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.13-mm1 +# Thu Sep 1 22:58:34 2005 +# +CONFIG_MIPS=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_KMOD=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y + +# +# Kernel type +# +CONFIG_32BIT=y +# CONFIG_64BIT is not set + +# +# Machine selection +# +# CONFIG_MACH_JAZZ is not set +CONFIG_MACH_VR41XX=y +# CONFIG_NEC_CMBVR4133 is not set +# CONFIG_CASIO_E55 is not set +# CONFIG_IBM_WORKPAD is not set +CONFIG_TANBAC_TB022X=y +# CONFIG_TANBAC_TB0226 is not set +CONFIG_TANBAC_TB0287=y +# CONFIG_VICTOR_MPC30X is not set +# CONFIG_ZAO_CAPCELLA is not set +CONFIG_PCI_VR41XX=y +# CONFIG_VRC4173 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_LASAT is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_MOMENCO_OCELOT_C is not set +# CONFIG_MOMENCO_OCELOT_3 is not set +# CONFIG_MOMENCO_JAGUAR_ATX is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_DDB5074 is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_QEMU is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SOC_AU1X00 is not set +# CONFIG_SIBYTE_SB1xxx_SOC is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_DMA_NEED_PCI_MAP_STATE=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_IRQ_CPU=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 + +# +# CPU selection +# +# CONFIG_CPU_MIPS32 is not set +# CONFIG_CPU_MIPS64 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +CONFIG_CPU_VR41XX=y +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_SYNC=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_PREEMPT is not set + +# +# Bus options (PCI, PCMCIA, EISA, ISA, TC) +# +CONFIG_HW_HAS_PCI=y +CONFIG_PCI=y +# CONFIG_PCI_LEGACY_PROC is not set +CONFIG_MMU=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_TRAD_SIGNALS=y + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +CONFIG_XFRM_USER=m +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_ASK_IP_FIB_HASH=y +# CONFIG_IP_FIB_TRIE is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +# CONFIG_NET_IPGRE_BROADCAST is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +CONFIG_INET_TUNNEL=m +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y + +# +# TCP congestion control +# +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_LBD is not set +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_IDEPCI_SHARE_IRQ is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +CONFIG_BLK_DEV_SIIMAGE=y +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_SPI is not set +# CONFIG_FUSION_FC is not set + +# +# IEEE 1394 (FireWire) support +# +CONFIG_IEEE1394=m + +# +# Subsystem Options +# +# CONFIG_IEEE1394_VERBOSEDEBUG is not set +# CONFIG_IEEE1394_OUI_DB is not set +CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y +CONFIG_IEEE1394_CONFIG_ROM_IP1394=y +# CONFIG_IEEE1394_EXPORT_FULL_API is not set + +# +# Device Drivers +# + +# +# Texas Instruments PCILynx requires I2C +# +CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_SBP2=m +# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_IEEE1394_RAWIO=m +CONFIG_IEEE1394_CMP=m +CONFIG_IEEE1394_AMDTP=m + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# PHY device support +# +# CONFIG_PHYLIB is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +CONFIG_R8169=y +# CONFIG_R8169_NAPI is not set +# CONFIG_SIS190 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_VR41XX=y +CONFIG_SERIAL_VR41XX_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_RTC_VR41XX is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_TANBAC_TB0219 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +CONFIG_GPIO_VR41XX=y +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Hardware Monitoring support +# +# CONFIG_HWMON is not set +# CONFIG_HWMON_VID is not set + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_OHCI_BIG_ENDIAN is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_ACECAD is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_ITMTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_KEYSPAN_REMOTE is not set +# CONFIG_USB_APPLETOUCH is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +CONFIG_USB_MON=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_GOTEMP is not set +# CONFIG_USB_PHIDGETKIT is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set + +# +# USB DSL modem support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# SN Devices +# + +# +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +# CONFIG_REISER4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set + +# +# XFS support +# +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +CONFIG_XFS_QUOTA=y +# CONFIG_XFS_SECURITY is not set +CONFIG_XFS_POSIX_ACL=y +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=m +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_QUOTACTL=y +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=y +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ASFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_CRAMFS=m +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CROSSCOMPILE=y +CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs" + +# +# Security options +# +CONFIG_KEYS=y +CONFIG_KEYS_DEBUG_PROC_KEYS=y +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=m +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_ISA_DMA_API=y diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index c53e4cb359ba7..83d81c9cdc2b3 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o obj-$(CONFIG_SNI_RM200_PCI) += fixup-sni.o ops-sni.o obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o +obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o obj-$(CONFIG_TOSHIBA_JMR3927) += fixup-jmr3927.o pci-jmr3927.o obj-$(CONFIG_TOSHIBA_RBTX4927) += fixup-rbtx4927.o ops-tx4927.o obj-$(CONFIG_VICTOR_MPC30X) += fixup-mpc30x.o diff --git a/arch/mips/pci/fixup-tb0287.c b/arch/mips/pci/fixup-tb0287.c new file mode 100644 index 0000000000000..8436d7f1fdb2d --- /dev/null +++ b/arch/mips/pci/fixup-tb0287.c @@ -0,0 +1,65 @@ +/* + * fixup-tb0287.c, The TANBAC TB0287 specific PCI fixups. + * + * Copyright (C) 2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * 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/init.h> +#include <linux/pci.h> + +#include <asm/vr41xx/tb0287.h> + +int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + unsigned char bus; + int irq = -1; + + bus = dev->bus->number; + if (bus == 0) { + switch (slot) { + case 16: + irq = TB0287_SM501_IRQ; + break; + case 17: + irq = TB0287_SIL680A_IRQ; + break; + default: + break; + } + } else if (bus == 1) { + switch (PCI_SLOT(dev->devfn)) { + case 0: + irq = TB0287_PCI_SLOT_IRQ; + break; + case 2: + case 3: + irq = TB0287_RTL8110_IRQ; + break; + default: + break; + } + } else if (bus > 1) { + irq = TB0287_PCI_SLOT_IRQ; + } + + return irq; +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} diff --git a/include/asm-mips/vr41xx/tb0287.h b/include/asm-mips/vr41xx/tb0287.h new file mode 100644 index 0000000000000..dd9832313afe3 --- /dev/null +++ b/include/asm-mips/vr41xx/tb0287.h @@ -0,0 +1,43 @@ +/* + * tb0287.h, Include file for TANBAC TB0287 mini-ITX board. + * + * Copyright (C) 2005 Media Lab Inc. <ito@mlb.co.jp> + * + * This code is largely based on tb0219.h. + * + * 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 + */ +#ifndef __TANBAC_TB0287_H +#define __TANBAC_TB0287_H + +#include <asm/vr41xx/vr41xx.h> + +/* + * General-Purpose I/O Pin Number + */ +#define TB0287_PCI_SLOT_PIN 2 +#define TB0287_SM501_PIN 3 +#define TB0287_SIL680A_PIN 8 +#define TB0287_RTL8110_PIN 13 + +/* + * Interrupt Number + */ +#define TB0287_PCI_SLOT_IRQ GIU_IRQ(TB0287_PCI_SLOT_PIN) +#define TB0287_SM501_IRQ GIU_IRQ(TB0287_SM501_PIN) +#define TB0287_SIL680A_IRQ GIU_IRQ(TB0287_SIL680A_PIN) +#define TB0287_RTL8110_IRQ GIU_IRQ(TB0287_RTL8110_PIN) + +#endif /* __TANBAC_TB0287_H */ -- GitLab From 4c7fc7220f6a3cce9b3f4bd66362176df67df577 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli <andrea@cpushare.com> Date: Fri, 9 Sep 2005 13:01:51 -0700 Subject: [PATCH 087/563] [PATCH] i386: seccomp fix for auditing/ptrace This is the same issue as ppc64 before, when returning to userland we shouldn't re-compute the seccomp check or the task could be killed during sigreturn when orig_eax is overwritten by the sigreturn syscall. This was found by Roland. This was harmless from a security standpoint, but some i686 users reported failures with auditing enabled system wide (some distro surprisingly makes it the default) and I reproduced it too by keeping the whole workload under strace -f. Patch is tested and works for me under strace -f. nobody@athlon:~/cpushare> strace -o /tmp/o -f python seccomp_test.py make: Nothing to be done for `seccomp_test'. Starting computing some malicious bytecode init load start stop receive_data failure kill exit_code 0 signal 9 The malicious bytecode has been killed successfully by seccomp Starting computing some safe bytecode init load start stop 174 counts kill exit_code 0 signal 0 The seccomp_test.py completed successfully, thank you for testing. (akpm: collaterally cleaned up a bit of do_syscall_trace() too) Signed-off-by: Andrea Arcangeli <andrea@cpushare.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/kernel/ptrace.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index 340980203b095..7b6368bf89746 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -694,17 +694,22 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) __attribute__((regparm(3))) int do_syscall_trace(struct pt_regs *regs, int entryexit) { - int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU), ret = 0; - /* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall - * interception. */ + int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU); + /* + * With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall + * interception + */ int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP); + int ret = 0; /* do the secure computing check first */ - secure_computing(regs->orig_eax); + if (!entryexit) + secure_computing(regs->orig_eax); if (unlikely(current->audit_context)) { if (entryexit) - audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax); + audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), + regs->eax); /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is * not used, entry.S will call us only on syscall exit, not @@ -738,7 +743,7 @@ int do_syscall_trace(struct pt_regs *regs, int entryexit) /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ /* Note that the debugger could change the result of test_thread_flag!*/ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80:0)); /* * this isn't the same as continuing with a signal, but it will do @@ -750,7 +755,7 @@ int do_syscall_trace(struct pt_regs *regs, int entryexit) current->exit_code = 0; } ret = is_sysemu; - out: +out: if (unlikely(current->audit_context) && !entryexit) audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax, regs->ebx, regs->ecx, regs->edx, regs->esi); @@ -759,6 +764,7 @@ int do_syscall_trace(struct pt_regs *regs, int entryexit) regs->orig_eax = -1; /* force skip of syscall restarting */ if (unlikely(current->audit_context)) - audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax); + audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), + regs->eax); return 1; } -- GitLab From fdf26d933a8171c2a5bd35b4a5ca3b099a216a35 Mon Sep 17 00:00:00 2001 From: Ashok Raj <ashok.raj@intel.com> Date: Fri, 9 Sep 2005 13:01:52 -0700 Subject: [PATCH 088/563] [PATCH] x86_64: Don't do broadcast IPIs when hotplug is enabled in flat mode. The use of non-shortcut version of routines breaking CPU hotplug. The option to select this via cmdline also is deleted with the physflat patch, hence directly placing this code under CONFIG_HOTPLUG_CPU. We dont want to use broadcast mode IPI's when hotplug is enabled. This causes bad effects in send IPI to a cpu that is offline which can trip when the cpu is in the process of being kicked alive. Signed-off-by: Ashok Raj <ashok.raj@intel.com> Acked-by: Andi Kleen <ak@muc.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/genapic_flat.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c index adc96282a9e21..6d57da96bf8c7 100644 --- a/arch/x86_64/kernel/genapic_flat.c +++ b/arch/x86_64/kernel/genapic_flat.c @@ -78,8 +78,18 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector) static void flat_send_IPI_allbutself(int vector) { +#ifndef CONFIG_HOTPLUG_CPU if (((num_online_cpus()) - 1) >= 1) __send_IPI_shortcut(APIC_DEST_ALLBUT, vector,APIC_DEST_LOGICAL); +#else + cpumask_t allbutme = cpu_online_map; + int me = get_cpu(); /* Ensure we are not preempted when we clear */ + cpu_clear(me, allbutme); + + if (!cpus_empty(allbutme)) + flat_send_IPI_mask(allbutme, vector); + put_cpu(); +#endif } static void flat_send_IPI_all(int vector) -- GitLab From 092c948811359d8715790af0eedefc7dff1cd619 Mon Sep 17 00:00:00 2001 From: Ashok Raj <ashok.raj@intel.com> Date: Fri, 9 Sep 2005 13:01:53 -0700 Subject: [PATCH 089/563] [PATCH] x86_64: Don't call enforce_max_cpus when hotplug is enabled enforce_max_cpus nukes out cpu_present_map and cpu_possible_map making it impossible to add new cpus in the system. Since it doesnt provide any additional value apart this call and reference is removed. Signed-off-by: Ashok Raj <ashok.raj@intel.com> Acked-by: Andi Kleen <ak@muc.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/smpboot.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 90aeccd151907..4fb34b5cb1f96 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -894,23 +894,6 @@ static __init void disable_smp(void) cpu_set(0, cpu_core_map[0]); } -/* - * Handle user cpus=... parameter. - */ -static __init void enforce_max_cpus(unsigned max_cpus) -{ - int i, k; - k = 0; - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_possible(i)) - continue; - if (++k > max_cpus) { - cpu_clear(i, cpu_possible_map); - cpu_clear(i, cpu_present_map); - } - } -} - #ifdef CONFIG_HOTPLUG_CPU /* * cpu_possible_map should be static, it cannot change as cpu's @@ -999,8 +982,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) current_cpu_data = boot_cpu_data; current_thread_info()->cpu = 0; /* needed? */ - enforce_max_cpus(max_cpus); - #ifdef CONFIG_HOTPLUG_CPU prefill_possible_map(); #endif -- GitLab From 69ac59647e66c1b53fb98fe8b6d0f2099cffad60 Mon Sep 17 00:00:00 2001 From: Chaskiel Grundman <cg2v@andrew.cmu.edu> Date: Fri, 9 Sep 2005 13:01:54 -0700 Subject: [PATCH 090/563] [PATCH] alpha: process_reloc_for_got confuses r_offset and r_addend arch/alpha/kernel/module.c:process_reloc_for_got(), which figures out how big the .got section for a module should be, appears to be confusing r_offset (the file offset that the relocation needs to be applied to) with r_addend (the offset of the relocation's actual target address from the address of the relocation's symbol). Because of this, one .got entry is allocated for each relocation instead of one each unique symbol/addend. In the module I am working with, this causes the .got section to be almost 10 times larger than it needs to be (75544 bytes instead of 7608 bytes). As the .got is accessed with global-pointer-relative instructions, it needs to be within the 64k gp "zone", and a 75544 byte .got clearly does not fit. The result of this is that relocation overflows are detected during module load and the load is aborted. Change struct got_entry/process_reloc_for_got to fix this. Acked-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/alpha/kernel/module.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c index fc271e316a388..aac6d4b22f7a2 100644 --- a/arch/alpha/kernel/module.c +++ b/arch/alpha/kernel/module.c @@ -47,7 +47,7 @@ module_free(struct module *mod, void *module_region) struct got_entry { struct got_entry *next; - Elf64_Addr r_offset; + Elf64_Sxword r_addend; int got_offset; }; @@ -57,14 +57,14 @@ process_reloc_for_got(Elf64_Rela *rela, { unsigned long r_sym = ELF64_R_SYM (rela->r_info); unsigned long r_type = ELF64_R_TYPE (rela->r_info); - Elf64_Addr r_offset = rela->r_offset; + Elf64_Sxword r_addend = rela->r_addend; struct got_entry *g; if (r_type != R_ALPHA_LITERAL) return; for (g = chains + r_sym; g ; g = g->next) - if (g->r_offset == r_offset) { + if (g->r_addend == r_addend) { if (g->got_offset == 0) { g->got_offset = *poffset; *poffset += 8; @@ -74,7 +74,7 @@ process_reloc_for_got(Elf64_Rela *rela, g = kmalloc (sizeof (*g), GFP_KERNEL); g->next = chains[r_sym].next; - g->r_offset = r_offset; + g->r_addend = r_addend; g->got_offset = *poffset; *poffset += 8; chains[r_sym].next = g; -- GitLab From ff55fe2075e3901db4dbdc00e0b44a71bef97afd Mon Sep 17 00:00:00 2001 From: Jason Baron <jbaron@redhat.com> Date: Fri, 9 Sep 2005 13:01:57 -0700 Subject: [PATCH 091/563] [PATCH] pty_chars_in_buffer oops fix The idea of this patch is to lock both sides of a ptmx/pty pair during line discipline changing. This is needed to ensure that say a poll on one side of the pty doesn't occur while the line discipline is actively being changed. This resulted in an oops reported on lkml, see: http://marc.theaimsgroup.com/?l=linux-kernel&m=111342171410005&w=2 A 'hacky' approach was previously implmemented which served to eliminate the poll vs. line discipline changing race. However, this patch takes a more general approach to the issue. The patch only adds locking on a less often used path, the line-discipline changing path, as opposed to locking the ptmx/pty pair on read/write/poll paths. The patch below, takes both ldisc locks in either order b/c the locks are both taken under the same spinlock(). I thought about locking the ptmx/pty separately, such as master always first but that introduces a 3 way deadlock. For example, process 1 does a blocking read on the slave side. Then, process 2 does an ldisc change on the slave side, which acquires the master ldisc lock but not the slave's. Finally, process 3 does a write which blocks on the process 2's ldisc reference. This patch does introduce some changes in semantics. For example, a line discipline change on side 'a' of a ptmx/pty pair, will now wait for a read/write to complete on the other side, or side 'b'. The current behavior is to simply wait for any read/writes on only side 'a', not both sides 'a' and 'b'. I think this behavior makes sense, but I wanted to point it out. I've tested the patch with a bunch of read/write/poll while changing the line discipline out from underneath. This patch obviates the need for the above "hide the problem" patch. Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/pty.c | 5 ++- drivers/char/tty_io.c | 79 +++++++++++++++++++++++++++++-------------- 2 files changed, 56 insertions(+), 28 deletions(-) diff --git a/drivers/char/pty.c b/drivers/char/pty.c index da32889d22c09..49f3997fd251d 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -149,15 +149,14 @@ static int pty_write_room(struct tty_struct *tty) static int pty_chars_in_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; - ssize_t (*chars_in_buffer)(struct tty_struct *); int count; /* We should get the line discipline lock for "tty->link" */ - if (!to || !(chars_in_buffer = to->ldisc.chars_in_buffer)) + if (!to || !to->ldisc.chars_in_buffer) return 0; /* The ldisc must report 0 if no characters available to be read */ - count = chars_in_buffer(to); + count = to->ldisc.chars_in_buffer(to); if (tty->driver->subtype == PTY_TYPE_SLAVE) return count; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 9d657127f313f..6a56ae4f77257 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -469,21 +469,19 @@ static void tty_ldisc_enable(struct tty_struct *tty) static int tty_set_ldisc(struct tty_struct *tty, int ldisc) { - int retval = 0; - struct tty_ldisc o_ldisc; + int retval = 0; + struct tty_ldisc o_ldisc; char buf[64]; int work; unsigned long flags; struct tty_ldisc *ld; + struct tty_struct *o_tty; if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) return -EINVAL; restart: - if (tty->ldisc.num == ldisc) - return 0; /* We are already in the desired discipline */ - ld = tty_ldisc_get(ldisc); /* Eduardo Blanco <ejbs@cs.cs.com.uy> */ /* Cyrus Durgin <cider@speakeasy.org> */ @@ -494,45 +492,74 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (ld == NULL) return -EINVAL; - o_ldisc = tty->ldisc; - tty_wait_until_sent(tty, 0); + if (tty->ldisc.num == ldisc) { + tty_ldisc_put(ldisc); + return 0; + } + + o_ldisc = tty->ldisc; + o_tty = tty->link; + /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit * prevents anyone taking a reference once it is clear. * We need the lock to avoid racing reference takers. */ - + spin_lock_irqsave(&tty_ldisc_lock, flags); - if(tty->ldisc.refcount) - { - /* Free the new ldisc we grabbed. Must drop the lock - first. */ + if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { + if(tty->ldisc.refcount) { + /* Free the new ldisc we grabbed. Must drop the lock + first. */ + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + tty_ldisc_put(ldisc); + /* + * There are several reasons we may be busy, including + * random momentary I/O traffic. We must therefore + * retry. We could distinguish between blocking ops + * and retries if we made tty_ldisc_wait() smarter. That + * is up for discussion. + */ + if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) + return -ERESTARTSYS; + goto restart; + } + if(o_tty && o_tty->ldisc.refcount) { + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + tty_ldisc_put(ldisc); + if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) + return -ERESTARTSYS; + goto restart; + } + } + + /* if the TTY_LDISC bit is set, then we are racing against another ldisc change */ + + if (!test_bit(TTY_LDISC, &tty->flags)) { spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(ldisc); - /* - * There are several reasons we may be busy, including - * random momentary I/O traffic. We must therefore - * retry. We could distinguish between blocking ops - * and retries if we made tty_ldisc_wait() smarter. That - * is up for discussion. - */ - if(wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) - return -ERESTARTSYS; + ld = tty_ldisc_ref_wait(tty); + tty_ldisc_deref(ld); goto restart; } - clear_bit(TTY_LDISC, &tty->flags); + + clear_bit(TTY_LDISC, &tty->flags); clear_bit(TTY_DONT_FLIP, &tty->flags); + if (o_tty) { + clear_bit(TTY_LDISC, &o_tty->flags); + clear_bit(TTY_DONT_FLIP, &o_tty->flags); + } spin_unlock_irqrestore(&tty_ldisc_lock, flags); - + /* * From this point on we know nobody has an ldisc * usage reference, nor can they obtain one until * we say so later on. */ - + work = cancel_delayed_work(&tty->flip.work); /* * Wait for ->hangup_work and ->flip.work handlers to terminate @@ -583,10 +610,12 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) */ tty_ldisc_enable(tty); + if (o_tty) + tty_ldisc_enable(o_tty); /* Restart it in case no characters kick it off. Safe if already running */ - if(work) + if (work) schedule_delayed_work(&tty->flip.work, 1); return retval; } -- GitLab From 28254d439b8c65f93cb331f5aa741efa6a8ec62f Mon Sep 17 00:00:00 2001 From: Samuel Thibault <samuel.thibault@ens-lyon.org> Date: Fri, 9 Sep 2005 13:01:58 -0700 Subject: [PATCH 092/563] [PATCH] vga text console and stty cols/rows Some people use 66-cells braille devices for reading the console, and hence would like to reduce the width of the screen by using: stty cols 66 However, the vga text console doesn't behave correctly: the 14 first characters of the second line are put on the right of the first line and so forth. Here is a patch to correct that. It corrects the disp_end and offset registers of the vga board on console resize and console switch. On usual screens, you then correctly get a right and/or bottom blank margin. On some laptop panels, the output is resized so that text actually gets magnified, which can be great for some people (see http://dept-info.labri.fr/~thibault/ls.jpg ). Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/console/vgacon.c | 71 +++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index d27fa91e58869..0705cd7414117 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -497,6 +497,57 @@ static void vgacon_cursor(struct vc_data *c, int mode) } } +static int vgacon_doresize(struct vc_data *c, + unsigned int width, unsigned int height) +{ + unsigned long flags; + unsigned int scanlines = height * c->vc_font.height; + u8 scanlines_lo, r7, vsync_end, mode; + + spin_lock_irqsave(&vga_lock, flags); + + outb_p(VGA_CRTC_MODE, vga_video_port_reg); + mode = inb_p(vga_video_port_val); + + if (mode & 0x04) + scanlines >>= 1; + + scanlines -= 1; + scanlines_lo = scanlines & 0xff; + + outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg); + r7 = inb_p(vga_video_port_val) & ~0x42; + + if (scanlines & 0x100) + r7 |= 0x02; + if (scanlines & 0x200) + r7 |= 0x40; + + /* deprotect registers */ + outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); + vsync_end = inb_p(vga_video_port_val); + outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); + outb_p(vsync_end & ~0x80, vga_video_port_val); + + outb_p(VGA_CRTC_H_DISP, vga_video_port_reg); + outb_p(width - 1, vga_video_port_val); + outb_p(VGA_CRTC_OFFSET, vga_video_port_reg); + outb_p(width >> 1, vga_video_port_val); + + outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg); + outb_p(scanlines_lo, vga_video_port_val); + outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg); + outb_p(r7,vga_video_port_val); + + /* reprotect registers */ + outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); + outb_p(vsync_end, vga_video_port_val); + + spin_unlock_irqrestore(&vga_lock, flags); + + return 0; +} + static int vgacon_switch(struct vc_data *c) { /* @@ -510,9 +561,13 @@ static int vgacon_switch(struct vc_data *c) /* We can only copy out the size of the video buffer here, * otherwise we get into VGA BIOS */ - if (!vga_is_gfx) + if (!vga_is_gfx) { scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, - c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); + c->vc_screenbuf_size > vga_vram_size ? + vga_vram_size : c->vc_screenbuf_size); + vgacon_doresize(c, c->vc_cols, c->vc_rows); + } + return 0; /* Redrawing not needed */ } @@ -962,6 +1017,17 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font) #endif +static int vgacon_resize(struct vc_data *c, unsigned int width, + unsigned int height) +{ + if (width % 2 || width > ORIG_VIDEO_COLS || height > ORIG_VIDEO_LINES) + return -EINVAL; + + if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ + vgacon_doresize(c, width, height); + return 0; +} + static int vgacon_scrolldelta(struct vc_data *c, int lines) { if (!lines) /* Turn scrollback off */ @@ -1103,6 +1169,7 @@ const struct consw vga_con = { .con_blank = vgacon_blank, .con_font_set = vgacon_font_set, .con_font_get = vgacon_font_get, + .con_resize = vgacon_resize, .con_set_palette = vgacon_set_palette, .con_scrolldelta = vgacon_scrolldelta, .con_set_origin = vgacon_set_origin, -- GitLab From f76baf9365bd66216bf0e0ebfc083e22eda6215b Mon Sep 17 00:00:00 2001 From: Alexander Krizhanovsky <klx@yandex.ru> Date: Fri, 9 Sep 2005 13:01:59 -0700 Subject: [PATCH 093/563] [PATCH] autofs: fix "busy inodes after umount..." This patch for old autofs (version 3) cleans dentries which are not putted after killing the automount daemon (it's analogue of recent patch for autofs4). Signed-off-by: Alexander Krizhanovsky <klx@yandex.ru> Cc: Ian Kent <raven@themaw.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/autofs/autofs_i.h | 3 ++- fs/autofs/dirhash.c | 5 +++-- fs/autofs/inode.c | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h index 6171431272dc2..990c28da5aece 100644 --- a/fs/autofs/autofs_i.h +++ b/fs/autofs/autofs_i.h @@ -105,6 +105,7 @@ struct autofs_sb_info { struct file *pipe; pid_t oz_pgrp; int catatonic; + struct super_block *sb; unsigned long exp_timeout; ino_t next_dir_ino; struct autofs_wait_queue *queues; /* Wait queue pointer */ @@ -134,7 +135,7 @@ void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *); void autofs_hash_delete(struct autofs_dir_ent *); struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *,struct autofs_dir_ent *); void autofs_hash_dputall(struct autofs_dirhash *); -void autofs_hash_nuke(struct autofs_dirhash *); +void autofs_hash_nuke(struct autofs_sb_info *); /* Expiration-handling functions */ diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c index 448143fd0796a..5ccfcf26310d7 100644 --- a/fs/autofs/dirhash.c +++ b/fs/autofs/dirhash.c @@ -232,13 +232,13 @@ void autofs_hash_dputall(struct autofs_dirhash *dh) /* Delete everything. This is used on filesystem destruction, so we make no attempt to keep the pointers valid */ -void autofs_hash_nuke(struct autofs_dirhash *dh) +void autofs_hash_nuke(struct autofs_sb_info *sbi) { int i; struct autofs_dir_ent *ent, *nent; for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) { - for ( ent = dh->h[i] ; ent ; ent = nent ) { + for ( ent = sbi->dirhash.h[i] ; ent ; ent = nent ) { nent = ent->next; if ( ent->dentry ) dput(ent->dentry); @@ -246,4 +246,5 @@ void autofs_hash_nuke(struct autofs_dirhash *dh) kfree(ent); } } + shrink_dcache_sb(sbi->sb); } diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index 4888c1fabbf71..65e5ed42190ed 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -27,7 +27,7 @@ static void autofs_put_super(struct super_block *sb) if ( !sbi->catatonic ) autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */ - autofs_hash_nuke(&sbi->dirhash); + autofs_hash_nuke(sbi); for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) { if ( test_bit(n, sbi->symlink_bitmap) ) kfree(sbi->symlink[n].data); @@ -148,6 +148,7 @@ int autofs_fill_super(struct super_block *s, void *data, int silent) s->s_magic = AUTOFS_SUPER_MAGIC; s->s_op = &autofs_sops; s->s_time_gran = 1; + sbi->sb = s; root_inode = iget(s, AUTOFS_ROOT_INO); root = d_alloc_root(root_inode); -- GitLab From b0d62e6d5b3318b6b722121d945afa295f7201b5 Mon Sep 17 00:00:00 2001 From: Jason Baron <jbaron@redhat.com> Date: Fri, 9 Sep 2005 13:02:01 -0700 Subject: [PATCH 094/563] [PATCH] fix disassociate_ctty vs. fork race Race is as follows. Process A forks process B, both being part of the same session. Then, A calls disassociate_ctty while B forks C: A B ==== ==== fork() copy_signal() dissasociate_ctty() .... attach_pid(p, PIDTYPE_SID, p->signal->session); Now, C can have current->signal->tty pointing to a freed tty structure, as it hasn't yet been added to the session group (to have its controlling tty cleared on the diassociate_ctty() call). This has shown up as an oops but could be even more serious. I haven't tried to create a test case, but a customer has verified that the patch below resolves the issue, which was occuring quite frequently. I'll try and post the test case if i can. The patch simply checks for a NULL tty *after* it has been attached to the proper session group and clears it as necessary. Alternatively, we could simply do the tty assignment after the the process is added to the proper session group. Signed-off-by: Jason Baron <jbaron@redhat.com> Cc: Roland McGrath <roland@redhat.com> Cc: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/fork.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/fork.c b/kernel/fork.c index dfeadf466f185..b25802065031e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1116,6 +1116,9 @@ static task_t *copy_process(unsigned long clone_flags, __get_cpu_var(process_counts)++; } + if (!current->signal->tty && p->signal->tty) + p->signal->tty = NULL; + nr_threads++; total_forks++; write_unlock_irq(&tasklist_lock); -- GitLab From 383f2835eb9afb723af71850037b2f074ac9db60 Mon Sep 17 00:00:00 2001 From: "Chen, Kenneth W" <kenneth.w.chen@intel.com> Date: Fri, 9 Sep 2005 13:02:02 -0700 Subject: [PATCH 095/563] [PATCH] Prefetch kernel stacks to speed up context switch For architecture like ia64, the switch stack structure is fairly large (currently 528 bytes). For context switch intensive application, we found that significant amount of cache misses occurs in switch_to() function. The following patch adds a hook in the schedule() function to prefetch switch stack structure as soon as 'next' task is determined. This allows maximum overlap in prefetch cache lines for that structure. Signed-off-by: Ken Chen <kenneth.w.chen@intel.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: "Luck, Tony" <tony.luck@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ia64/kernel/entry.S | 23 +++++++++++++++++++++++ include/asm-ia64/system.h | 1 + include/linux/sched.h | 5 +++++ kernel/sched.c | 1 + 4 files changed, 30 insertions(+) diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 3c88210245099..915e127918365 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -470,6 +470,29 @@ ENTRY(load_switch_stack) br.cond.sptk.many b7 END(load_switch_stack) +GLOBAL_ENTRY(prefetch_stack) + add r14 = -IA64_SWITCH_STACK_SIZE, sp + add r15 = IA64_TASK_THREAD_KSP_OFFSET, in0 + ;; + ld8 r16 = [r15] // load next's stack pointer + lfetch.fault.excl [r14], 128 + ;; + lfetch.fault.excl [r14], 128 + lfetch.fault [r16], 128 + ;; + lfetch.fault.excl [r14], 128 + lfetch.fault [r16], 128 + ;; + lfetch.fault.excl [r14], 128 + lfetch.fault [r16], 128 + ;; + lfetch.fault.excl [r14], 128 + lfetch.fault [r16], 128 + ;; + lfetch.fault [r16], 128 + br.ret.sptk.many rp +END(prefetch_switch_stack) + GLOBAL_ENTRY(execve) mov r15=__NR_execve // put syscall number in place break __BREAK_SYSCALL diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h index 33256db4a7cf1..635235fa1e326 100644 --- a/include/asm-ia64/system.h +++ b/include/asm-ia64/system.h @@ -275,6 +275,7 @@ extern void ia64_load_extra (struct task_struct *task); */ #define __ARCH_WANT_UNLOCKED_CTXSW +#define ARCH_HAS_PREFETCH_SWITCH_STACK #define ia64_platform_is(x) (strcmp(x, platform_name) == 0) void cpu_idle_wait(void); diff --git a/include/linux/sched.h b/include/linux/sched.h index ea1b5f32ec5c1..c551e6a1447e5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -604,6 +604,11 @@ extern int groups_search(struct group_info *group_info, gid_t grp); #define GROUP_AT(gi, i) \ ((gi)->blocks[(i)/NGROUPS_PER_BLOCK][(i)%NGROUPS_PER_BLOCK]) +#ifdef ARCH_HAS_PREFETCH_SWITCH_STACK +extern void prefetch_stack(struct task_struct*); +#else +static inline void prefetch_stack(struct task_struct *t) { } +#endif struct audit_context; /* See audit.c */ struct mempolicy; diff --git a/kernel/sched.c b/kernel/sched.c index 18b95520a2e29..2632b812cf24a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2888,6 +2888,7 @@ asmlinkage void __sched schedule(void) if (next == rq->idle) schedstat_inc(rq, sched_goidle); prefetch(next); + prefetch_stack(next); clear_tsk_need_resched(prev); rcu_qsctr_inc(task_cpu(prev)); -- GitLab From fac92becdaecff64dd91daab0292c5131de92f0d Mon Sep 17 00:00:00 2001 From: Andrew Stribblehill <a.d.stribblehill@durham.ac.uk> Date: Fri, 9 Sep 2005 13:02:04 -0700 Subject: [PATCH 096/563] [PATCH] bfs: fix endianness, signedness; add trivial bugfix * Makes BFS code endianness-clean. * Fixes some signedness warnings. * Fixes a problem in fs/bfs/inode.c:164 where inodes not synced to disk don't get fully marked as clean. Here's how to reproduce it: # mount -o loop -t bfs /bfs.img /mnt # df -i /mnt Filesystem Inodes IUsed IFree IUse% Mounted on /bfs.img 48 1 47 3% /mnt # df -k /mnt Filesystem 1K-blocks Used Available Use% Mounted on /bfs.img 512 5 508 1% /mnt # cp 60k-archive.zip /mnt/mt.zip # df -k /mnt Filesystem 1K-blocks Used Available Use% Mounted on /bfs.img 512 65 447 13% /mnt # df -i /mnt Filesystem Inodes IUsed IFree IUse% Mounted on /bfs.img 48 2 46 5% /mnt # rm /mnt/mt.zip # echo $? 0 [If the unlink happens before the buffers flush, the following happens:] # df -i /mnt Filesystem Inodes IUsed IFree IUse% Mounted on /bfs.img 48 2 46 5% /mnt # df -k /mnt Filesystem 1K-blocks Used Available Use% Mounted on /bfs.img 512 65 447 13% /mnt fs/bfs/bfs.h | 1 Signed-off-by: Andrew Stribblehill <ads@wompom.org> Cc: <tigran@veritas.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/bfs/bfs.h | 1 - fs/bfs/dir.c | 25 +++++----- fs/bfs/file.c | 23 ++++++---- fs/bfs/inode.c | 102 ++++++++++++++++++++++------------------- include/linux/bfs_fs.h | 23 +++++----- 5 files changed, 93 insertions(+), 81 deletions(-) diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h index 1020dbc88bec0..1fbc53f14aba9 100644 --- a/fs/bfs/bfs.h +++ b/fs/bfs/bfs.h @@ -20,7 +20,6 @@ struct bfs_sb_info { unsigned long si_lasti; unsigned long * si_imap; struct buffer_head * si_sbh; /* buffer header w/superblock */ - struct bfs_super_block * si_bfs_sb; /* superblock in si_sbh->b_data */ }; /* diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 5a1e5ce057ff6..e240c335eb231 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c @@ -2,6 +2,7 @@ * fs/bfs/dir.c * BFS directory operations. * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> + * Made endianness-clean by Andrew Stribblehill <ads@wompom.org> 2005 */ #include <linux/time.h> @@ -20,9 +21,9 @@ #define dprintf(x...) #endif -static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino); +static int bfs_add_entry(struct inode * dir, const unsigned char * name, int namelen, int ino); static struct buffer_head * bfs_find_entry(struct inode * dir, - const char * name, int namelen, struct bfs_dirent ** res_dir); + const unsigned char * name, int namelen, struct bfs_dirent ** res_dir); static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir) { @@ -53,7 +54,7 @@ static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir) de = (struct bfs_dirent *)(bh->b_data + offset); if (de->ino) { int size = strnlen(de->name, BFS_NAMELEN); - if (filldir(dirent, de->name, size, f->f_pos, de->ino, DT_UNKNOWN) < 0) { + if (filldir(dirent, de->name, size, f->f_pos, le16_to_cpu(de->ino), DT_UNKNOWN) < 0) { brelse(bh); unlock_kernel(); return 0; @@ -107,7 +108,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode, inode->i_mapping->a_ops = &bfs_aops; inode->i_mode = mode; inode->i_ino = ino; - BFS_I(inode)->i_dsk_ino = ino; + BFS_I(inode)->i_dsk_ino = cpu_to_le16(ino); BFS_I(inode)->i_sblock = 0; BFS_I(inode)->i_eblock = 0; insert_inode_hash(inode); @@ -139,7 +140,7 @@ static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry, st lock_kernel(); bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); if (bh) { - unsigned long ino = le32_to_cpu(de->ino); + unsigned long ino = (unsigned long)le16_to_cpu(de->ino); brelse(bh); inode = iget(dir->i_sb, ino); if (!inode) { @@ -183,7 +184,7 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry) inode = dentry->d_inode; lock_kernel(); bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); - if (!bh || de->ino != inode->i_ino) + if (!bh || le16_to_cpu(de->ino) != inode->i_ino) goto out_brelse; if (!inode->i_nlink) { @@ -224,7 +225,7 @@ static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry, old_dentry->d_name.name, old_dentry->d_name.len, &old_de); - if (!old_bh || old_de->ino != old_inode->i_ino) + if (!old_bh || le16_to_cpu(old_de->ino) != old_inode->i_ino) goto end_rename; error = -EPERM; @@ -270,7 +271,7 @@ struct inode_operations bfs_dir_inops = { .rename = bfs_rename, }; -static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino) +static int bfs_add_entry(struct inode * dir, const unsigned char * name, int namelen, int ino) { struct buffer_head * bh; struct bfs_dirent * de; @@ -304,7 +305,7 @@ static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int } dir->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(dir); - de->ino = ino; + de->ino = cpu_to_le16((u16)ino); for (i=0; i<BFS_NAMELEN; i++) de->name[i] = (i < namelen) ? name[i] : 0; mark_buffer_dirty(bh); @@ -317,7 +318,7 @@ static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int return -ENOSPC; } -static inline int bfs_namecmp(int len, const char * name, const char * buffer) +static inline int bfs_namecmp(int len, const unsigned char * name, const char * buffer) { if (len < BFS_NAMELEN && buffer[len]) return 0; @@ -325,7 +326,7 @@ static inline int bfs_namecmp(int len, const char * name, const char * buffer) } static struct buffer_head * bfs_find_entry(struct inode * dir, - const char * name, int namelen, struct bfs_dirent ** res_dir) + const unsigned char * name, int namelen, struct bfs_dirent ** res_dir) { unsigned long block, offset; struct buffer_head * bh; @@ -346,7 +347,7 @@ static struct buffer_head * bfs_find_entry(struct inode * dir, } de = (struct bfs_dirent *)(bh->b_data + offset); offset += BFS_DIRENT_SIZE; - if (de->ino && bfs_namecmp(namelen, name, de->name)) { + if (le16_to_cpu(de->ino) && bfs_namecmp(namelen, name, de->name)) { *res_dir = de; return bh; } diff --git a/fs/bfs/file.c b/fs/bfs/file.c index 747fd1ea55e0c..807723b65daf3 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -40,8 +40,8 @@ static int bfs_move_block(unsigned long from, unsigned long to, struct super_blo return 0; } -static int bfs_move_blocks(struct super_block *sb, unsigned long start, unsigned long end, - unsigned long where) +static int bfs_move_blocks(struct super_block *sb, unsigned long start, + unsigned long end, unsigned long where) { unsigned long i; @@ -57,20 +57,21 @@ static int bfs_move_blocks(struct super_block *sb, unsigned long start, unsigned static int bfs_get_block(struct inode * inode, sector_t block, struct buffer_head * bh_result, int create) { - long phys; + unsigned long phys; int err; struct super_block *sb = inode->i_sb; struct bfs_sb_info *info = BFS_SB(sb); struct bfs_inode_info *bi = BFS_I(inode); struct buffer_head *sbh = info->si_sbh; - if (block < 0 || block > info->si_blocks) + if (block > info->si_blocks) return -EIO; phys = bi->i_sblock + block; if (!create) { if (phys <= bi->i_eblock) { - dprintf("c=%d, b=%08lx, phys=%08lx (granted)\n", create, block, phys); + dprintf("c=%d, b=%08lx, phys=%09lx (granted)\n", + create, (unsigned long)block, phys); map_bh(bh_result, sb, phys); } return 0; @@ -80,7 +81,7 @@ static int bfs_get_block(struct inode * inode, sector_t block, of blocks allocated for this file, we can grant it */ if (inode->i_size && phys <= bi->i_eblock) { dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", - create, block, phys); + create, (unsigned long)block, phys); map_bh(bh_result, sb, phys); return 0; } @@ -88,11 +89,12 @@ static int bfs_get_block(struct inode * inode, sector_t block, /* the rest has to be protected against itself */ lock_kernel(); - /* if the last data block for this file is the last allocated block, we can - extend the file trivially, without moving it anywhere */ + /* if the last data block for this file is the last allocated + block, we can extend the file trivially, without moving it + anywhere */ if (bi->i_eblock == info->si_lf_eblk) { dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", - create, block, phys); + create, (unsigned long)block, phys); map_bh(bh_result, sb, phys); info->si_freeb -= phys - bi->i_eblock; info->si_lf_eblk = bi->i_eblock = phys; @@ -114,7 +116,8 @@ static int bfs_get_block(struct inode * inode, sector_t block, } else err = 0; - dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n", create, block, phys); + dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n", + create, (unsigned long)block, phys); bi->i_sblock = phys; phys += block; info->si_lf_eblk = bi->i_eblock = phys; diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 628c2c1a7d7e4..c7b39aa279d71 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -3,6 +3,8 @@ * BFS superblock and inode operations. * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> * From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds. + * + * Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005. */ #include <linux/module.h> @@ -54,46 +56,50 @@ static void bfs_read_inode(struct inode * inode) off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK; di = (struct bfs_inode *)bh->b_data + off; - inode->i_mode = 0x0000FFFF & di->i_mode; - if (di->i_vtype == BFS_VDIR) { + inode->i_mode = 0x0000FFFF & le32_to_cpu(di->i_mode); + if (le32_to_cpu(di->i_vtype) == BFS_VDIR) { inode->i_mode |= S_IFDIR; inode->i_op = &bfs_dir_inops; inode->i_fop = &bfs_dir_operations; - } else if (di->i_vtype == BFS_VREG) { + } else if (le32_to_cpu(di->i_vtype) == BFS_VREG) { inode->i_mode |= S_IFREG; inode->i_op = &bfs_file_inops; inode->i_fop = &bfs_file_operations; inode->i_mapping->a_ops = &bfs_aops; } - inode->i_uid = di->i_uid; - inode->i_gid = di->i_gid; - inode->i_nlink = di->i_nlink; + BFS_I(inode)->i_sblock = le32_to_cpu(di->i_sblock); + BFS_I(inode)->i_eblock = le32_to_cpu(di->i_eblock); + inode->i_uid = le32_to_cpu(di->i_uid); + inode->i_gid = le32_to_cpu(di->i_gid); + inode->i_nlink = le32_to_cpu(di->i_nlink); inode->i_size = BFS_FILESIZE(di); inode->i_blocks = BFS_FILEBLOCKS(di); + if (inode->i_size || inode->i_blocks) dprintf("Registered inode with %lld size, %ld blocks\n", inode->i_size, inode->i_blocks); inode->i_blksize = PAGE_SIZE; - inode->i_atime.tv_sec = di->i_atime; - inode->i_mtime.tv_sec = di->i_mtime; - inode->i_ctime.tv_sec = di->i_ctime; + inode->i_atime.tv_sec = le32_to_cpu(di->i_atime); + inode->i_mtime.tv_sec = le32_to_cpu(di->i_mtime); + inode->i_ctime.tv_sec = le32_to_cpu(di->i_ctime); inode->i_atime.tv_nsec = 0; inode->i_mtime.tv_nsec = 0; inode->i_ctime.tv_nsec = 0; - BFS_I(inode)->i_dsk_ino = di->i_ino; /* can be 0 so we store a copy */ - BFS_I(inode)->i_sblock = di->i_sblock; - BFS_I(inode)->i_eblock = di->i_eblock; + BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino); /* can be 0 so we store a copy */ brelse(bh); } static int bfs_write_inode(struct inode * inode, int unused) { - unsigned long ino = inode->i_ino; + unsigned int ino = (u16)inode->i_ino; + unsigned long i_sblock; struct bfs_inode * di; struct buffer_head * bh; int block, off; + dprintf("ino=%08x\n", ino); + if (ino < BFS_ROOT_INO || ino > BFS_SB(inode->i_sb)->si_lasti) { - printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino); + printf("Bad inode number %s:%08x\n", inode->i_sb->s_id, ino); return -EIO; } @@ -101,7 +107,7 @@ static int bfs_write_inode(struct inode * inode, int unused) block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1; bh = sb_bread(inode->i_sb, block); if (!bh) { - printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id, ino); + printf("Unable to read inode %s:%08x\n", inode->i_sb->s_id, ino); unlock_kernel(); return -EIO; } @@ -109,24 +115,26 @@ static int bfs_write_inode(struct inode * inode, int unused) off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK; di = (struct bfs_inode *)bh->b_data + off; - if (inode->i_ino == BFS_ROOT_INO) - di->i_vtype = BFS_VDIR; + if (ino == BFS_ROOT_INO) + di->i_vtype = cpu_to_le32(BFS_VDIR); else - di->i_vtype = BFS_VREG; - - di->i_ino = inode->i_ino; - di->i_mode = inode->i_mode; - di->i_uid = inode->i_uid; - di->i_gid = inode->i_gid; - di->i_nlink = inode->i_nlink; - di->i_atime = inode->i_atime.tv_sec; - di->i_mtime = inode->i_mtime.tv_sec; - di->i_ctime = inode->i_ctime.tv_sec; - di->i_sblock = BFS_I(inode)->i_sblock; - di->i_eblock = BFS_I(inode)->i_eblock; - di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1; + di->i_vtype = cpu_to_le32(BFS_VREG); + + di->i_ino = cpu_to_le16(ino); + di->i_mode = cpu_to_le32(inode->i_mode); + di->i_uid = cpu_to_le32(inode->i_uid); + di->i_gid = cpu_to_le32(inode->i_gid); + di->i_nlink = cpu_to_le32(inode->i_nlink); + di->i_atime = cpu_to_le32(inode->i_atime.tv_sec); + di->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); + di->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); + i_sblock = BFS_I(inode)->i_sblock; + di->i_sblock = cpu_to_le32(i_sblock); + di->i_eblock = cpu_to_le32(BFS_I(inode)->i_eblock); + di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1); mark_buffer_dirty(bh); + dprintf("Written ino=%d into %d:%d\n",le16_to_cpu(di->i_ino),block,off); brelse(bh); unlock_kernel(); return 0; @@ -140,13 +148,14 @@ static void bfs_delete_inode(struct inode * inode) int block, off; struct super_block * s = inode->i_sb; struct bfs_sb_info * info = BFS_SB(s); + struct bfs_inode_info * bi = BFS_I(inode); - dprintf("ino=%08lx\n", inode->i_ino); + dprintf("ino=%08lx\n", ino); truncate_inode_pages(&inode->i_data, 0); - if (inode->i_ino < BFS_ROOT_INO || inode->i_ino > info->si_lasti) { - printf("invalid ino=%08lx\n", inode->i_ino); + if (ino < BFS_ROOT_INO || ino > info->si_lasti) { + printf("invalid ino=%08lx\n", ino); return; } @@ -162,13 +171,13 @@ static void bfs_delete_inode(struct inode * inode) return; } off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK; - di = (struct bfs_inode *)bh->b_data + off; - if (di->i_ino) { - info->si_freeb += BFS_FILEBLOCKS(di); + di = (struct bfs_inode *) bh->b_data + off; + if (bi->i_dsk_ino) { + info->si_freeb += 1 + bi->i_eblock - bi->i_sblock; info->si_freei++; - clear_bit(di->i_ino, info->si_imap); + clear_bit(ino, info->si_imap); dump_imap("delete_inode", s); - } + } di->i_ino = 0; di->i_sblock = 0; mark_buffer_dirty(bh); @@ -274,14 +283,14 @@ static struct super_operations bfs_sops = { void dump_imap(const char *prefix, struct super_block * s) { -#if 0 +#ifdef DEBUG int i; char *tmpbuf = (char *)get_zeroed_page(GFP_KERNEL); if (!tmpbuf) return; for (i=BFS_SB(s)->si_lasti; i>=0; i--) { - if (i>PAGE_SIZE-100) break; + if (i > PAGE_SIZE-100) break; if (test_bit(i, BFS_SB(s)->si_imap)) strcat(tmpbuf, "1"); else @@ -297,7 +306,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) struct buffer_head * bh; struct bfs_super_block * bfs_sb; struct inode * inode; - int i, imap_len; + unsigned i, imap_len; struct bfs_sb_info * info; info = kmalloc(sizeof(*info), GFP_KERNEL); @@ -312,19 +321,18 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) if(!bh) goto out; bfs_sb = (struct bfs_super_block *)bh->b_data; - if (bfs_sb->s_magic != BFS_MAGIC) { + if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) { if (!silent) printf("No BFS filesystem on %s (magic=%08x)\n", - s->s_id, bfs_sb->s_magic); + s->s_id, le32_to_cpu(bfs_sb->s_magic)); goto out; } if (BFS_UNCLEAN(bfs_sb, s) && !silent) printf("%s is unclean, continuing\n", s->s_id); s->s_magic = BFS_MAGIC; - info->si_bfs_sb = bfs_sb; info->si_sbh = bh; - info->si_lasti = (bfs_sb->s_start - BFS_BSIZE)/sizeof(struct bfs_inode) + info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE)/sizeof(struct bfs_inode) + BFS_ROOT_INO - 1; imap_len = info->si_lasti/8 + 1; @@ -348,8 +356,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) goto out; } - info->si_blocks = (bfs_sb->s_end + 1)>>BFS_BSIZE_BITS; /* for statfs(2) */ - info->si_freeb = (bfs_sb->s_end + 1 - bfs_sb->s_start)>>BFS_BSIZE_BITS; + info->si_blocks = (le32_to_cpu(bfs_sb->s_end) + 1)>>BFS_BSIZE_BITS; /* for statfs(2) */ + info->si_freeb = (le32_to_cpu(bfs_sb->s_end) + 1 - cpu_to_le32(bfs_sb->s_start))>>BFS_BSIZE_BITS; info->si_freei = 0; info->si_lf_eblk = 0; info->si_lf_sblk = 0; diff --git a/include/linux/bfs_fs.h b/include/linux/bfs_fs.h index f7f0913cd110d..c1237aa92e384 100644 --- a/include/linux/bfs_fs.h +++ b/include/linux/bfs_fs.h @@ -14,8 +14,9 @@ #define BFS_INODES_PER_BLOCK 8 /* SVR4 vnode type values (bfs_inode->i_vtype) */ -#define BFS_VDIR 2 -#define BFS_VREG 1 +#define BFS_VDIR 2L +#define BFS_VREG 1L + /* BFS inode layout on disk */ struct bfs_inode { @@ -58,22 +59,22 @@ struct bfs_super_block { __u32 s_padding[118]; }; -#define BFS_NZFILESIZE(ip) \ - (((ip)->i_eoffset + 1) - (ip)->i_sblock * BFS_BSIZE) - -#define BFS_FILESIZE(ip) \ - ((ip)->i_sblock == 0 ? 0 : BFS_NZFILESIZE(ip)) - -#define BFS_FILEBLOCKS(ip) \ - ((ip)->i_sblock == 0 ? 0 : ((ip)->i_eblock + 1) - (ip)->i_sblock) #define BFS_OFF2INO(offset) \ ((((offset) - BFS_BSIZE) / sizeof(struct bfs_inode)) + BFS_ROOT_INO) #define BFS_INO2OFF(ino) \ ((__u32)(((ino) - BFS_ROOT_INO) * sizeof(struct bfs_inode)) + BFS_BSIZE) +#define BFS_NZFILESIZE(ip) \ + ((cpu_to_le32((ip)->i_eoffset) + 1) - cpu_to_le32((ip)->i_sblock) * BFS_BSIZE) + +#define BFS_FILESIZE(ip) \ + ((ip)->i_sblock == 0 ? 0 : BFS_NZFILESIZE(ip)) +#define BFS_FILEBLOCKS(ip) \ + ((ip)->i_sblock == 0 ? 0 : (cpu_to_le32((ip)->i_eblock) + 1) - cpu_to_le32((ip)->i_sblock)) #define BFS_UNCLEAN(bfs_sb, sb) \ - ((bfs_sb->s_from != -1) && (bfs_sb->s_to != -1) && !(sb->s_flags & MS_RDONLY)) + ((cpu_to_le32(bfs_sb->s_from) != -1) && (cpu_to_le32(bfs_sb->s_to) != -1) && !(sb->s_flags & MS_RDONLY)) + #endif /* _LINUX_BFS_FS_H */ -- GitLab From 6f519165a97924ab3eeb99f388718d12ff97f1f4 Mon Sep 17 00:00:00 2001 From: Deepak Saxena <dsaxena@plexity.net> Date: Fri, 9 Sep 2005 13:02:07 -0700 Subject: [PATCH 097/563] [PATCH] cs89x0: add netpoll support Signed-off-by: Deepak Saxena <dsaxena@plexity.net> Cc: Matt Mackall <mpm@selenic.com> Cc: Jeff Garzik <jgarzik@pobox.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/net/cs89x0.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index b780307093eb1..cdc07ccd7332f 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -247,6 +247,9 @@ static int get_eeprom_data(struct net_device *dev, int off, int len, int *buffer static int get_eeprom_cksum(int off, int len, int *buffer); static int set_mac_address(struct net_device *dev, void *addr); static void count_rx_errors(int status, struct net_local *lp); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void net_poll_controller(struct net_device *dev); +#endif #if ALLOW_DMA static void get_dma_channel(struct net_device *dev); static void release_dma_buff(struct net_local *lp); @@ -405,6 +408,19 @@ get_eeprom_cksum(int off, int len, int *buffer) return -1; } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling receive - used by netconsole and other diagnostic tools + * to allow network i/o with interrupts disabled. + */ +static void net_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + net_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + /* This is the real probe routine. Linux has a history of friendly device probes on the ISA bus. A good device probes avoids doing writes, and verifies that the correct device exists and functions. @@ -760,6 +776,9 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) dev->get_stats = net_get_stats; dev->set_multicast_list = set_multicast_list; dev->set_mac_address = set_mac_address; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = net_poll_controller; +#endif printk("\n"); if (net_debug) -- GitLab From 8f58202bf6b915656e116ece3bc4ace14bfe533a Mon Sep 17 00:00:00 2001 From: Wendy Cheng <wcheng@redhat.com> Date: Fri, 9 Sep 2005 13:02:08 -0700 Subject: [PATCH 098/563] [PATCH] change io_cancel return code for no cancel case Note that other than few exceptions, most of the current filesystem and/or drivers do not have aio cancel specifically defined (kiob->ki_cancel field is mostly NULL). However, sys_io_cancel system call universally sets return code to -EAGAIN. This gives applications a wrong impression that this call is implemented but just never works. We have customer inquires about this issue. Changed by Benjamin LaHaise to EINVAL instead of ENOSYS Signed-off-by: S. Wendy Cheng <wcheng@redhat.com> Acked-by: Benjamin LaHaise <bcrl@kvack.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/aio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/aio.c b/fs/aio.c index 4f641abac3c09..769791df36b4f 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1673,7 +1673,7 @@ asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, ret = -EFAULT; } } else - printk(KERN_DEBUG "iocb has no cancel operation\n"); + ret = -EINVAL; put_ioctx(ctx); -- GitLab From ac0b1bc1edbe81c0cb36cad7e7f5b91f4d9e12ed Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise <bcrl@linux.intel.com> Date: Fri, 9 Sep 2005 13:02:09 -0700 Subject: [PATCH 099/563] [PATCH] aio: kiocb locking to serialise retry and cancel Implement a per-kiocb lock to serialise retry operations and cancel. This is done using wait_on_bit_lock() on the KIF_LOCKED bit of kiocb->ki_flags. Also, make the cancellation path lock the kiocb and subsequently release all references to it if the cancel was successful. This version includes a fix for the deadlock with __aio_run_iocbs. Signed-off-by: Benjamin LaHaise <bcrl@linux.intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/aio.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/fs/aio.c b/fs/aio.c index 769791df36b4f..201c1847fa07b 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -546,6 +546,24 @@ struct kioctx *lookup_ioctx(unsigned long ctx_id) return ioctx; } +static int lock_kiocb_action(void *param) +{ + schedule(); + return 0; +} + +static inline void lock_kiocb(struct kiocb *iocb) +{ + wait_on_bit_lock(&iocb->ki_flags, KIF_LOCKED, lock_kiocb_action, + TASK_UNINTERRUPTIBLE); +} + +static inline void unlock_kiocb(struct kiocb *iocb) +{ + kiocbClearLocked(iocb); + wake_up_bit(&iocb->ki_flags, KIF_LOCKED); +} + /* * use_mm * Makes the calling kernel thread take on the specified @@ -786,7 +804,9 @@ static int __aio_run_iocbs(struct kioctx *ctx) * Hold an extra reference while retrying i/o. */ iocb->ki_users++; /* grab extra reference */ + lock_kiocb(iocb); aio_run_iocb(iocb); + unlock_kiocb(iocb); if (__aio_put_req(ctx, iocb)) /* drop extra ref */ put_ioctx(ctx); } @@ -1527,10 +1547,9 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, goto out_put_req; spin_lock_irq(&ctx->ctx_lock); - if (likely(list_empty(&ctx->run_list))) { - aio_run_iocb(req); - } else { - list_add_tail(&req->ki_run_list, &ctx->run_list); + aio_run_iocb(req); + unlock_kiocb(req); + if (!list_empty(&ctx->run_list)) { /* drain the run list */ while (__aio_run_iocbs(ctx)) ; @@ -1661,6 +1680,7 @@ asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, if (NULL != cancel) { struct io_event tmp; pr_debug("calling cancel\n"); + lock_kiocb(kiocb); memset(&tmp, 0, sizeof(tmp)); tmp.obj = (u64)(unsigned long)kiocb->ki_obj.user; tmp.data = kiocb->ki_user_data; @@ -1672,6 +1692,7 @@ asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, if (copy_to_user(result, &tmp, sizeof(tmp))) ret = -EFAULT; } + unlock_kiocb(kiocb); } else ret = -EINVAL; -- GitLab From 73a358d1892a8233801e3fd54668075b52ec42da Mon Sep 17 00:00:00 2001 From: KUROSAWA Takahiro <kurosawa@valinux.co.jp> Date: Fri, 9 Sep 2005 13:02:10 -0700 Subject: [PATCH 100/563] [PATCH] fix for cpusets minor problem This patch fixes minor problem that the CPUSETS have when files in the cpuset filesystem are read after lseek()-ed beyond the EOF. Signed-off-by: KUROSAWA Takahiro <kurosawa@valinux.co.jp> Acked-by: Paul Jackson <pj@sgi.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/cpuset.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 1f06e76901067..712d02029971e 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -972,6 +972,10 @@ static ssize_t cpuset_common_file_read(struct file *file, char __user *buf, *s++ = '\n'; *s = '\0'; + /* Do nothing if *ppos is at the eof or beyond the eof. */ + if (s - page <= *ppos) + return 0; + start = page + *ppos; n = s - start; retval = n - copy_to_user(buf, start, min(n, nbytes)); -- GitLab From 24b20ac6e1c80082889b3d6ae08aadda777519e5 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Date: Fri, 9 Sep 2005 13:02:11 -0700 Subject: [PATCH 101/563] [PATCH] remove unnecessary handle_IRQ_event() prototypes The function prototype for handle_IRQ_event() in a few architctures is not needed because they use GENERIC_HARDIRQ. Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-mips/irq.h | 3 --- include/asm-ppc/irq.h | 4 ---- include/asm-sh/irq.h | 4 ---- include/asm-x86_64/irq.h | 4 ---- 4 files changed, 15 deletions(-) diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h index b90b11d0b886b..3f2470e9e6780 100644 --- a/include/asm-mips/irq.h +++ b/include/asm-mips/irq.h @@ -49,7 +49,4 @@ do { \ extern void arch_init_irq(void); -struct irqaction; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif /* _ASM_IRQ_H */ diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h index b4b270457eddc..55752474d0d94 100644 --- a/include/asm-ppc/irq.h +++ b/include/asm-ppc/irq.h @@ -404,9 +404,5 @@ extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; extern unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; extern atomic_t ppc_n_lost_interrupts; -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #endif /* _ASM_IRQ_H */ #endif /* __KERNEL__ */ diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h index 831e52ee45b59..614a8c13b7216 100644 --- a/include/asm-sh/irq.h +++ b/include/asm-sh/irq.h @@ -587,10 +587,6 @@ static inline int generic_irq_demux(int irq) #define irq_canonicalize(irq) (irq) #define irq_demux(irq) __irq_demux(sh_mv.mv_irq_demux(irq)) -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #if defined(CONFIG_CPU_SUBTYPE_SH73180) #include <asm/irq-sh73180.h> #endif diff --git a/include/asm-x86_64/irq.h b/include/asm-x86_64/irq.h index 4482657777bbd..fb724ba37ae63 100644 --- a/include/asm-x86_64/irq.h +++ b/include/asm-x86_64/irq.h @@ -48,10 +48,6 @@ static __inline__ int irq_canonicalize(int irq) #define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */ #endif -struct irqaction; -struct pt_regs; -int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); - #ifdef CONFIG_HOTPLUG_CPU #include <linux/cpumask.h> extern void fixup_irqs(cpumask_t map); -- GitLab From 9d5c1e1bf2b906966609f8cf4a844e61adb86bcd Mon Sep 17 00:00:00 2001 From: Andrew Morton <akpm@osdl.org> Date: Fri, 9 Sep 2005 13:02:12 -0700 Subject: [PATCH 102/563] [PATCH] deadline: clean up question mark operator That ?: trick gives us the creeps. Cc: Jens Axboe <axboe@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/block/deadline-iosched.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c index 24594c57c3230..52a3ae5289a09 100644 --- a/drivers/block/deadline-iosched.c +++ b/drivers/block/deadline-iosched.c @@ -512,7 +512,10 @@ static int deadline_dispatch_requests(struct deadline_data *dd) /* * batches are currently reads XOR writes */ - drq = dd->next_drq[WRITE] ? : dd->next_drq[READ]; + if (dd->next_drq[WRITE]) + drq = dd->next_drq[WRITE]; + else + drq = dd->next_drq[READ]; if (drq) { /* we have a "next request" */ -- GitLab From 4a918bc233c8b9537fbc05a8bbb33928a4980cc5 Mon Sep 17 00:00:00 2001 From: Paul Fulghum <paulkf@microgate.com> Date: Fri, 9 Sep 2005 13:02:12 -0700 Subject: [PATCH 103/563] [PATCH] synclink.c: compiler optimisation fix Make some fields of DMA descriptor volatile to prevent compiler optimizations. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/synclink.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 37c8bea8e2b00..747eb8d18166d 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 4.28 2004/08/11 19:30:01 paulkf Exp $ + * $Id: synclink.c,v 4.37 2005/09/07 13:13:19 paulkf Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -141,9 +141,9 @@ static MGSL_PARAMS default_params = { typedef struct _DMABUFFERENTRY { u32 phys_addr; /* 32-bit flat physical address of data buffer */ - u16 count; /* buffer size/data count */ - u16 status; /* Control/status field */ - u16 rcc; /* character count field */ + volatile u16 count; /* buffer size/data count */ + volatile u16 status; /* Control/status field */ + volatile u16 rcc; /* character count field */ u16 reserved; /* padding required by 16C32 */ u32 link; /* 32-bit flat link to next buffer entry */ char *virt_addr; /* virtual address of data buffer */ @@ -896,7 +896,7 @@ module_param_array(txdmabufs, int, NULL, 0); module_param_array(txholdbufs, int, NULL, 0); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "$Revision: 4.28 $"; +static char *driver_version = "$Revision: 4.37 $"; static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); -- GitLab From 9661239f7f698ba3a79db5e8ab5bb2f4090663d9 Mon Sep 17 00:00:00 2001 From: Paul Fulghum <paulkf@microgate.com> Date: Fri, 9 Sep 2005 13:02:13 -0700 Subject: [PATCH 104/563] [PATCH] synclink.c: add clear stats Add the ability to clear statistics. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/synclink.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 747eb8d18166d..26b421b74bb61 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1814,6 +1814,8 @@ static int startup(struct mgsl_struct * info) info->pending_bh = 0; + memset(&info->icount, 0, sizeof(info->icount)); + init_timer(&info->tx_timer); info->tx_timer.data = (unsigned long)info; info->tx_timer.function = mgsl_tx_timeout; @@ -2470,12 +2472,12 @@ static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount __user * printk("%s(%d):mgsl_get_params(%s)\n", __FILE__,__LINE__, info->device_name); - COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount)); - if (err) { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):mgsl_get_stats(%s) user buffer copy failed\n", - __FILE__,__LINE__,info->device_name); - return -EFAULT; + if (!user_icount) { + memset(&info->icount, 0, sizeof(info->icount)); + } else { + COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); + if (err) + return -EFAULT; } return 0; -- GitLab From 7c1fff58cfaaf1c4b6a31a569e18cb7d2d8db0a6 Mon Sep 17 00:00:00 2001 From: Paul Fulghum <paulkf@microgate.com> Date: Fri, 9 Sep 2005 13:02:14 -0700 Subject: [PATCH 105/563] [PATCH] synclink.c: add loopback to async mode Add internal loopback support for asynchronous mode operation. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/synclink.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 26b421b74bb61..ea2d54be4843e 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -6151,6 +6151,11 @@ static void usc_set_async_mode( struct mgsl_struct *info ) usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12)); } + if (info->params.loopback) { + info->loopback_bits = 0x300; + outw(0x0300, info->io_base + CCAR); + } + } /* end of usc_set_async_mode() */ /* usc_loopback_frame() -- GitLab From 7f3edb94564d319cd58cc11c2c986b7ec25643d8 Mon Sep 17 00:00:00 2001 From: Paul Fulghum <paulkf@microgate.com> Date: Fri, 9 Sep 2005 13:02:14 -0700 Subject: [PATCH 106/563] [PATCH] synclinkmp.c: fix double mapping of signals Serial signals were incorrectly mapped twice to events. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/synclinkmp.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 8982eafd0fb71..1bde04d66cde5 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -1,5 +1,5 @@ /* - * $Id: synclinkmp.c,v 4.34 2005/03/04 15:07:10 paulkf Exp $ + * $Id: synclinkmp.c,v 4.38 2005/07/15 13:29:44 paulkf Exp $ * * Device driver for Microgate SyncLink Multiport * high speed multiprotocol serial adapter. @@ -486,7 +486,7 @@ module_param_array(maxframe, int, NULL, 0); module_param_array(dosyncppp, int, NULL, 0); static char *driver_name = "SyncLink MultiPort driver"; -static char *driver_version = "$Revision: 4.34 $"; +static char *driver_version = "$Revision: 4.38 $"; static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static void synclinkmp_remove_one(struct pci_dev *dev); @@ -555,7 +555,6 @@ static int set_txidle(SLMP_INFO *info, int idle_mode); static int tx_enable(SLMP_INFO *info, int enable); static int tx_abort(SLMP_INFO *info); static int rx_enable(SLMP_INFO *info, int enable); -static int map_status(int signals); static int modem_input_wait(SLMP_INFO *info,int arg); static int wait_mgsl_event(SLMP_INFO *info, int __user *mask_ptr); static int tiocmget(struct tty_struct *tty, struct file *file); @@ -3108,16 +3107,6 @@ static int rx_enable(SLMP_INFO * info, int enable) return 0; } -static int map_status(int signals) -{ - /* Map status bits to API event bits */ - - return ((signals & SerialSignal_DSR) ? MgslEvent_DsrActive : MgslEvent_DsrInactive) + - ((signals & SerialSignal_CTS) ? MgslEvent_CtsActive : MgslEvent_CtsInactive) + - ((signals & SerialSignal_DCD) ? MgslEvent_DcdActive : MgslEvent_DcdInactive) + - ((signals & SerialSignal_RI) ? MgslEvent_RiActive : MgslEvent_RiInactive); -} - /* wait for specified event to occur */ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr) @@ -3144,7 +3133,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr) /* return immediately if state matches requested events */ get_signals(info); - s = map_status(info->serial_signals); + s = info->serial_signals; events = mask & ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + -- GitLab From 761a444d8d059e4e2de326383b1dec4a636e0a92 Mon Sep 17 00:00:00 2001 From: Paul Fulghum <paulkf@microgate.com> Date: Fri, 9 Sep 2005 13:02:15 -0700 Subject: [PATCH 107/563] [PATCH] synclinkmp.c: disable burst transfers Disable burst transfers on adapter local bus. Hardware feature does not work on latest version of adapter. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/synclinkmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 1bde04d66cde5..d55dbf1f9e183 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -643,7 +643,7 @@ static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation le static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes static u32 misc_ctrl_value = 0x007e4040; -static u32 lcr1_brdr_value = 0x00800029; +static u32 lcr1_brdr_value = 0x00800028; static u32 read_ahead_count = 8; -- GitLab From 166692e4a045348109f66b493e1b41afde6f3769 Mon Sep 17 00:00:00 2001 From: Paul Fulghum <paulkf@microgate.com> Date: Fri, 9 Sep 2005 13:02:16 -0700 Subject: [PATCH 108/563] [PATCH] synclinkmp.c: add statistics clear Add ability to clear statistics. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/synclinkmp.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index d55dbf1f9e183..eb31a3b865df2 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -2748,6 +2748,8 @@ static int startup(SLMP_INFO * info) info->pending_bh = 0; + memset(&info->icount, 0, sizeof(info->icount)); + /* program hardware for current parameters */ reset_port(info); @@ -2951,12 +2953,12 @@ static int get_stats(SLMP_INFO * info, struct mgsl_icount __user *user_icount) printk("%s(%d):%s get_params()\n", __FILE__,__LINE__, info->device_name); - COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount)); - if (err) { - if ( debug_level >= DEBUG_LEVEL_INFO ) - printk( "%s(%d):%s get_stats() user buffer copy failed\n", - __FILE__,__LINE__,info->device_name); - return -EFAULT; + if (!user_icount) { + memset(&info->icount, 0, sizeof(info->icount)); + } else { + COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); + if (err) + return -EFAULT; } return 0; -- GitLab From 6e8dcee3e63f5a2cba4affff4bbb6e228f4b258a Mon Sep 17 00:00:00 2001 From: Paul Fulghum <paulkf@microgate.com> Date: Fri, 9 Sep 2005 13:02:17 -0700 Subject: [PATCH 109/563] [PATCH] synclinkmp.c: fix async internal loopback Fix async internal loopback by not using enable_loopback function which reprograms clocking and should only be used for hdlc mode. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/synclinkmp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index eb31a3b865df2..6fb165cf8a61c 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -4479,11 +4479,13 @@ void async_mode(SLMP_INFO *info) /* MD2, Mode Register 2 * * 07..02 Reserved, must be 0 - * 01..00 CNCT<1..0> Channel connection, 0=normal + * 01..00 CNCT<1..0> Channel connection, 00=normal 11=local loopback * * 0000 0000 */ RegValue = 0x00; + if (info->params.loopback) + RegValue |= (BIT1 + BIT0); write_reg(info, MD2, RegValue); /* RXS, Receive clock source @@ -4564,9 +4566,6 @@ void async_mode(SLMP_INFO *info) write_reg(info, IE2, info->ie2_value); set_rate( info, info->params.data_rate * 16 ); - - if (info->params.loopback) - enable_loopback(info,1); } /* Program the SCA for HDLC communications. -- GitLab From 59f4e7d572980a521b7bdba74ab71b21f5995538 Mon Sep 17 00:00:00 2001 From: Truxton Fulton <trux@truxton.com> Date: Fri, 9 Sep 2005 13:02:18 -0700 Subject: [PATCH 110/563] [PATCH] fix reboot via keyboard controller reset I have a system (Biostar IDEQ210M mini-pc with a VIA chipset) which will not reboot unless a keyboard is plugged in to it. I have tried all combinations of the kernel "reboot=x,y" flags to no avail. Rebooting by any method will leave the system in a wedged state (at the "Restarting system" message). I finally tracked the problem down to the machine's refusal to fully reboot unless the keyboard controller status register had bit 2 set. This is the "System flag" which when set, indicates successful completion of the keyboard controller self-test (Basic Assurance Test, BAT). I suppose that something is trying to protect against sporadic reboots unless the keyboard controller is in a good state (a keyboard is present), but I need this machine to be headless. I found that setting the system flag (via the command byte) before giving the "pulse reset line" command will allow the reboot to proceed. The patch is simple, and I think it should be fine for everybody whether they have this type of machine or not. This affects the "hard" reboot (as done when the kernel boot flags "reboot=c,h" are used). Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-i386/mach-default/mach_reboot.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/asm-i386/mach-default/mach_reboot.h b/include/asm-i386/mach-default/mach_reboot.h index 521e227db679f..06ae4d81ba6a6 100644 --- a/include/asm-i386/mach-default/mach_reboot.h +++ b/include/asm-i386/mach-default/mach_reboot.h @@ -22,7 +22,15 @@ static inline void mach_reboot(void) for (i = 0; i < 100; i++) { kb_wait(); udelay(50); - outb(0xfe, 0x64); /* pulse reset low */ + outb(0x60, 0x64); /* write Controller Command Byte */ + udelay(50); + kb_wait(); + udelay(50); + outb(0x14, 0x60); /* set "System flag" */ + udelay(50); + kb_wait(); + udelay(50); + outb(0xfe, 0x64); /* pulse reset low */ udelay(50); } } -- GitLab From a8d995c99ef56a3dbcdbe291bb71658bf00e9ad6 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach <js@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:19 -0700 Subject: [PATCH 111/563] [PATCH] dvb: email address update Update email address of Peter Hettkamp. Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/bt878.c | 2 +- drivers/media/dvb/bt8xx/bt878.h | 2 +- drivers/media/dvb/bt8xx/dvb-bt8xx.h | 2 +- drivers/media/dvb/frontends/cx24110.c | 2 +- drivers/media/dvb/frontends/cx24110.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 3c5a8e273c4aa..3bfbba3d9dfc2 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -1,7 +1,7 @@ /* * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card * - * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> + * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> * * large parts based on the bttv driver * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de) diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index 837623f7fcdfc..a73baf00ca390 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -1,7 +1,7 @@ /* bt878.h - Bt878 audio module (register offsets) - Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> + Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> 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/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h index 2923b3b0dd3ce..9ec8e5bd6c1fa 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h @@ -2,7 +2,7 @@ * Bt8xx based DVB adapter driver * * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org> - * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> + * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> * Copyright (C) 1999-2001 Ralph Metzler & Marcus Metzler for convergence integrated media GmbH * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> * diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 8222b88cb4868..555d472e42ded 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -1,7 +1,7 @@ /* cx24110 - Single Chip Satellite Channel Receiver driver module - Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on + Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on work Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h index 6b663f4744e00..b63ecf26421a0 100644 --- a/drivers/media/dvb/frontends/cx24110.h +++ b/drivers/media/dvb/frontends/cx24110.h @@ -1,7 +1,7 @@ /* cx24110 - Single Chip Satellite Channel Receiver driver module - Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on + Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on work Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> -- GitLab From 34f7373aaec80564cc87b7829e4e2a0e3c20c4b7 Mon Sep 17 00:00:00 2001 From: Olaf Hering <olh@suse.de> Date: Fri, 9 Sep 2005 13:02:20 -0700 Subject: [PATCH 112/563] [PATCH] dvb: remove version.h dependencies Remove all #include <linux/version.h> and all references to LINUX_VERSION_CODE and KERNEL_VERSION. Based on patch by Olaf Hering. Signed-off-by: Olaf Hering <olh@suse.de> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/common/saa7146_fops.c | 1 - drivers/media/common/saa7146_i2c.c | 5 ----- drivers/media/dvb/cinergyT2/cinergyT2.c | 1 - drivers/media/dvb/dvb-core/dvb_net.c | 5 ----- drivers/media/dvb/frontends/dib3000mb.c | 1 - drivers/media/dvb/frontends/dib3000mc.c | 1 - drivers/media/dvb/ttusb-dec/ttusb_dec.c | 1 - include/media/saa7146.h | 13 +------------ 8 files changed, 1 insertion(+), 27 deletions(-) diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index c04fd11526e08..37888989ea2e3 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -1,5 +1,4 @@ #include <media/saa7146_vv.h> -#include <linux/version.h> #define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && dev->vv_data->vbi_minor != -1) diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 6284894505c6f..45f86737699aa 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -1,4 +1,3 @@ -#include <linux/version.h> #include <media/saa7146_vv.h> static u32 saa7146_i2c_func(struct i2c_adapter *adapter) @@ -402,12 +401,8 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c saa7146_i2c_reset(dev); if( NULL != i2c_adapter ) { -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) - i2c_adapter->data = dev; -#else BUG_ON(!i2c_adapter->class); i2c_set_adapdata(i2c_adapter,dev); -#endif i2c_adapter->algo = &saa7146_algo; i2c_adapter->algo_data = NULL; i2c_adapter->id = I2C_HW_SAA7146; diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 9ea5747b12110..c52e9d5c3d96d 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -25,7 +25,6 @@ #include <linux/config.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/version.h> #include <linux/slab.h> #include <linux/usb.h> #include <linux/pci.h> diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 6a968c346a367..33a357c48a19a 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -62,7 +62,6 @@ #include <linux/uio.h> #include <asm/uaccess.h> #include <linux/crc32.h> -#include <linux/version.h> #include "dvb_demux.h" #include "dvb_net.h" @@ -171,11 +170,7 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb, skb->mac.raw=skb->data; skb_pull(skb,dev->hard_header_len); -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8) - eth = skb->mac.ethernet; -#else eth = eth_hdr(skb); -#endif if (*eth->h_dest & 1) { if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index cd434b7cf9db6..21433e1831e74 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -23,7 +23,6 @@ #include <linux/config.h> #include <linux/kernel.h> -#include <linux/version.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index cd33705a4320b..441de665fec32 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -22,7 +22,6 @@ */ #include <linux/config.h> #include <linux/kernel.h> -#include <linux/version.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 45c9a9a08e4d8..3d08fc83a7541 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -28,7 +28,6 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/usb.h> -#include <linux/version.h> #include <linux/interrupt.h> #include <linux/firmware.h> #include <linux/crc32.h> diff --git a/include/media/saa7146.h b/include/media/saa7146.h index 3dfb8d670eb78..2a897c3a6a9af 100644 --- a/include/media/saa7146.h +++ b/include/media/saa7146.h @@ -1,7 +1,6 @@ #ifndef __SAA7146__ #define __SAA7146__ -#include <linux/version.h> /* for version macros */ #include <linux/module.h> /* for module-version */ #include <linux/delay.h> /* for delay-stuff */ #include <linux/slab.h> /* for kmalloc/kfree */ @@ -15,12 +14,7 @@ #include <linux/vmalloc.h> /* for vmalloc() */ #include <linux/mm.h> /* for vmalloc_to_page() */ -/* ugly, but necessary to build the dvb stuff under 2.4. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) - #include "dvb_functions.h" -#endif - -#define SAA7146_VERSION_CODE KERNEL_VERSION(0,5,0) +#define SAA7146_VERSION_CODE 0x000500 /* 0.5.0 */ #define saa7146_write(sxy,adr,dat) writel((dat),(sxy->mem+(adr))) #define saa7146_read(sxy,adr) readl(sxy->mem+(adr)) @@ -33,13 +27,8 @@ extern unsigned int saa7146_debug; #define DEBUG_VARIABLE saa7146_debug #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) -#define DEBUG_PROLOG printk("%s: %s(): ",__stringify(KBUILD_BASENAME),__FUNCTION__) -#define INFO(x) { printk("%s: ",__stringify(KBUILD_BASENAME)); printk x; } -#else #define DEBUG_PROLOG printk("%s: %s(): ",__stringify(KBUILD_MODNAME),__FUNCTION__) #define INFO(x) { printk("%s: ",__stringify(KBUILD_MODNAME)); printk x; } -#endif #define ERR(x) { DEBUG_PROLOG; printk x; } -- GitLab From 3cc2176cbbee6adfaceac2df6d77312cf30cee83 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach <js@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:20 -0700 Subject: [PATCH 113/563] [PATCH] dvb: avoid building empty built-in.o Don't build empty built-in.o when DVB/V4L is not configured. Thanks to Sam Ravnborg and Keith Owens. Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 772d6112fb3b6..c578a529e7a8e 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -2,4 +2,7 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := video/ radio/ dvb/ common/ +obj-y := common/ +obj-$(CONFIG_VIDEO_DEV) += video/ +obj-$(CONFIG_VIDEO_DEV) += radio/ +obj-$(CONFIG_DVB) += dvb/ -- GitLab From c05100528efe997a27d841230f9f5b2f4adf3d0f Mon Sep 17 00:00:00 2001 From: Andreas Oberritter <obi@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:21 -0700 Subject: [PATCH 114/563] [PATCH] dvb: core: glue code for DMX_GET_CAPS and DMX_SET_SOURCE Glue code for DMX_GET_CAPS and DMX_SET_SOURCE ioctls. Signed-off-by: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-core/demux.h | 5 +++++ drivers/media/dvb/dvb-core/dmxdev.c | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h index fb55eaa5c8e70..b86d03f5100bf 100644 --- a/drivers/media/dvb/dvb-core/demux.h +++ b/drivers/media/dvb/dvb-core/demux.h @@ -30,6 +30,7 @@ #include <linux/errno.h> #include <linux/list.h> #include <linux/time.h> +#include <linux/dvb/dmx.h> /*--------------------------------------------------------------------------*/ /* Common definitions */ @@ -282,6 +283,10 @@ struct dmx_demux { int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids); + int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps); + + int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src); + int (*get_stc) (struct dmx_demux* demux, unsigned int num, u64 *stc, unsigned int *base); }; diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 68050cd527cb4..6059562f4d424 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -929,6 +929,22 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, dmxdev->demux->get_pes_pids(dmxdev->demux, (u16 *)parg); break; + case DMX_GET_CAPS: + if (!dmxdev->demux->get_caps) { + ret = -EINVAL; + break; + } + ret = dmxdev->demux->get_caps(dmxdev->demux, parg); + break; + + case DMX_SET_SOURCE: + if (!dmxdev->demux->set_source) { + ret = -EINVAL; + break; + } + ret = dmxdev->demux->set_source(dmxdev->demux, parg); + break; + case DMX_GET_STC: if (!dmxdev->demux->get_stc) { ret=-EINVAL; -- GitLab From 1e0ae280e91a4f69b08770c6ab72808711dd4f2b Mon Sep 17 00:00:00 2001 From: Andreas Oberritter <obi@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:22 -0700 Subject: [PATCH 115/563] [PATCH] dvb: core: dvb_demux: fix continuity counter error handling Don't return immediately from dvb_dmx_swfilter_section_packet() if CC is not ok. Otherwise a new feed drops all packets until the first packet with CC=0 arrives. Signed-off-by: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-core/dvb_demux.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index ac9889d222882..3d18d3eebcff3 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -336,7 +336,6 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 */ feed->pusi_seen = 0; dvb_dmx_swfilter_section_new(feed); - return 0; } if (buf[1] & 0x40) { -- GitLab From 936534676ef6c6af389eb9e61de7d725ee79a316 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter <obi@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:23 -0700 Subject: [PATCH 116/563] [PATCH] dvb: core: dvb_demux: remove unused cruft Removed some useless functions and variables. Signed-off-by: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-core/demux.h | 13 --------- drivers/media/dvb/dvb-core/dvb_demux.c | 39 ++------------------------ drivers/media/dvb/dvb-core/dvb_demux.h | 2 +- 3 files changed, 3 insertions(+), 51 deletions(-) diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h index b86d03f5100bf..608461f090fed 100644 --- a/drivers/media/dvb/dvb-core/demux.h +++ b/drivers/media/dvb/dvb-core/demux.h @@ -245,7 +245,6 @@ struct dmx_frontend { struct dmx_demux { u32 capabilities; /* Bitfield of capability flags */ struct dmx_frontend* frontend; /* Front-end connected to the demux */ - struct list_head reg_list; /* List of registered demuxes */ void* priv; /* Pointer to private data of the API client */ int users; /* Number of users */ int (*open) (struct dmx_demux* demux); @@ -291,16 +290,4 @@ struct dmx_demux { u64 *stc, unsigned int *base); }; -/*--------------------------------------------------------------------------*/ -/* Demux directory */ -/*--------------------------------------------------------------------------*/ - -/* - * DMX_DIR_ENTRY(): Casts elements in the list of registered - * demuxes from the generic type struct list_head* to the type struct dmx_demux - *. - */ - -#define DMX_DIR_ENTRY(list) list_entry(list, struct dmx_demux, reg_list) - #endif /* #ifndef __DEMUX_H */ diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 3d18d3eebcff3..8774a94ef01bd 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -39,33 +39,6 @@ // #define DVB_DEMUX_SECTION_LOSS_LOG -static LIST_HEAD(dmx_muxs); - - -static int dmx_register_demux(struct dmx_demux *demux) -{ - demux->users = 0; - list_add(&demux->reg_list, &dmx_muxs); - return 0; -} - -static int dmx_unregister_demux(struct dmx_demux* demux) -{ - struct list_head *pos, *n, *head=&dmx_muxs; - - list_for_each_safe (pos, n, head) { - if (DMX_DIR_ENTRY(pos) == demux) { - if (demux->users>0) - return -EINVAL; - list_del(pos); - return 0; - } - } - - return -ENODEV; -} - - /****************************************************************************** * static inlined helper functions ******************************************************************************/ @@ -1207,7 +1180,7 @@ static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids) int dvb_dmx_init(struct dvb_demux *dvbdemux) { - int i, err; + int i; struct dmx_demux *dmx = &dvbdemux->dmx; dvbdemux->users = 0; @@ -1250,7 +1223,6 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dvbdemux->memcopy = dvb_dmx_memcopy; dmx->frontend = NULL; - dmx->reg_list.prev = dmx->reg_list.next = &dmx->reg_list; dmx->priv = (void *) dvbdemux; dmx->open = dvbdmx_open; dmx->close = dvbdmx_close; @@ -1273,21 +1245,14 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) sema_init(&dvbdemux->mutex, 1); spin_lock_init(&dvbdemux->lock); - if ((err = dmx_register_demux(dmx)) < 0) - return err; - return 0; } EXPORT_SYMBOL(dvb_dmx_init); -int dvb_dmx_release(struct dvb_demux *dvbdemux) +void dvb_dmx_release(struct dvb_demux *dvbdemux) { - struct dmx_demux *dmx = &dvbdemux->dmx; - - dmx_unregister_demux(dmx); vfree(dvbdemux->filter); vfree(dvbdemux->feed); - return 0; } EXPORT_SYMBOL(dvb_dmx_release); diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h index c09beb3916225..20275a2f6ec69 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.h +++ b/drivers/media/dvb/dvb-core/dvb_demux.h @@ -138,7 +138,7 @@ struct dvb_demux { int dvb_dmx_init(struct dvb_demux *dvbdemux); -int dvb_dmx_release(struct dvb_demux *dvbdemux); +void dvb_dmx_release(struct dvb_demux *dvbdemux); void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, size_t count); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count); -- GitLab From 218721b8ef334a7c778fe3bc033922edef911a1f Mon Sep 17 00:00:00 2001 From: Andreas Oberritter <obi@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:24 -0700 Subject: [PATCH 117/563] [PATCH] dvb: core: dvb_demux: remove unsused descramble callbacks Removed unused descramble_mac_address and descramble_section_payload callbacks. Signed-off-by: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-core/demux.h | 11 ----------- drivers/media/dvb/dvb-core/dvb_demux.c | 3 --- 2 files changed, 14 deletions(-) diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h index 608461f090fed..ee5be59759ee3 100644 --- a/drivers/media/dvb/dvb-core/demux.h +++ b/drivers/media/dvb/dvb-core/demux.h @@ -260,17 +260,6 @@ struct dmx_demux { dmx_section_cb callback); int (*release_section_feed) (struct dmx_demux* demux, struct dmx_section_feed* feed); - int (*descramble_mac_address) (struct dmx_demux* demux, - u8* buffer1, - size_t buffer1_length, - u8* buffer2, - size_t buffer2_length, - u16 pid); - int (*descramble_section_payload) (struct dmx_demux* demux, - u8* buffer1, - size_t buffer1_length, - u8* buffer2, size_t buffer2_length, - u16 pid); int (*add_frontend) (struct dmx_demux* demux, struct dmx_frontend* frontend); int (*remove_frontend) (struct dmx_demux* demux, diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 8774a94ef01bd..6488206f54c88 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -1232,9 +1232,6 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dmx->allocate_section_feed = dvbdmx_allocate_section_feed; dmx->release_section_feed = dvbdmx_release_section_feed; - dmx->descramble_mac_address = NULL; - dmx->descramble_section_payload = NULL; - dmx->add_frontend = dvbdmx_add_frontend; dmx->remove_frontend = dvbdmx_remove_frontend; dmx->get_frontends = dvbdmx_get_frontends; -- GitLab From 5d2cd1631e97f5eb9c8666ff9cd8011cd5c12e7d Mon Sep 17 00:00:00 2001 From: Andreas Oberritter <obi@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:24 -0700 Subject: [PATCH 118/563] [PATCH] dvb: core: dvb_demux: remove more unused cruft Removed more unused variables and constants. Signed-off-by: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-core/demux.h | 7 ------- drivers/media/dvb/dvb-core/dmxdev.c | 4 ++-- drivers/media/dvb/dvb-core/dvb_demux.c | 18 ++---------------- drivers/media/dvb/dvb-core/dvb_demux.h | 7 +------ drivers/media/dvb/dvb-core/dvb_net.c | 4 +--- 5 files changed, 6 insertions(+), 34 deletions(-) diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h index ee5be59759ee3..9719a3b30f786 100644 --- a/drivers/media/dvb/dvb-core/demux.h +++ b/drivers/media/dvb/dvb-core/demux.h @@ -125,9 +125,7 @@ struct dmx_ts_feed { u16 pid, int type, enum dmx_ts_pes pes_type, - size_t callback_length, size_t circular_buffer_size, - int descramble, struct timespec timeout); int (*start_filtering) (struct dmx_ts_feed* feed); int (*stop_filtering) (struct dmx_ts_feed* feed); @@ -160,7 +158,6 @@ struct dmx_section_feed { int (*set) (struct dmx_section_feed* feed, u16 pid, size_t circular_buffer_size, - int descramble, int check_crc); int (*allocate_filter) (struct dmx_section_feed* feed, struct dmx_section_filter** filter); @@ -208,7 +205,6 @@ struct dmx_frontend { struct list_head connectivity_list; /* List of front-ends that can be connected to a particular demux */ - void* priv; /* Pointer to private data of the API client */ enum dmx_frontend_source source; }; @@ -226,8 +222,6 @@ struct dmx_frontend { #define DMX_MEMORY_BASED_FILTERING 8 /* write() available */ #define DMX_CRC_CHECKING 16 #define DMX_TS_DESCRAMBLING 32 -#define DMX_SECTION_PAYLOAD_DESCRAMBLING 64 -#define DMX_MAC_ADDRESS_DESCRAMBLING 128 /* * Demux resource type identifier. @@ -246,7 +240,6 @@ struct dmx_demux { u32 capabilities; /* Bitfield of capability flags */ struct dmx_frontend* frontend; /* Front-end connected to the demux */ void* priv; /* Pointer to private data of the API client */ - int users; /* Number of users */ int (*open) (struct dmx_demux* demux); int (*close) (struct dmx_demux* demux); int (*write) (struct dmx_demux* demux, const char* buf, size_t count); diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 6059562f4d424..8028c3a5e287c 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -571,7 +571,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) return ret; } - ret=(*secfeed)->set(*secfeed, para->pid, 32768, 0, + ret=(*secfeed)->set(*secfeed, para->pid, 32768, (para->flags & DMX_CHECK_CRC) ? 1 : 0); if (ret<0) { @@ -654,7 +654,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) (*tsfeed)->priv = (void *) filter; ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes, - 188, 32768, 0, timeout); + 32768, timeout); if (ret < 0) { dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 6488206f54c88..b9cb671b938cc 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -577,8 +577,7 @@ static void dvb_demux_feed_del(struct dvb_demux_feed *feed) } static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, - enum dmx_ts_pes pes_type, size_t callback_length, - size_t circular_buffer_size, int descramble, + enum dmx_ts_pes pes_type, size_t circular_buffer_size, struct timespec timeout) { struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed; @@ -610,17 +609,10 @@ static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, feed->pid = pid; feed->buffer_size = circular_buffer_size; - feed->descramble = descramble; feed->timeout = timeout; - feed->cb_length = callback_length; feed->ts_type = ts_type; feed->pes_type = pes_type; - if (feed->descramble) { - up(&demux->mutex); - return -ENOSYS; - } - if (feed->buffer_size) { #ifdef NOBUFS feed->buffer=NULL; @@ -819,7 +811,7 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed* feed, static int dmx_section_feed_set(struct dmx_section_feed* feed, u16 pid, size_t circular_buffer_size, - int descramble, int check_crc) + int check_crc) { struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; @@ -834,12 +826,6 @@ static int dmx_section_feed_set(struct dmx_section_feed* feed, dvbdmxfeed->pid = pid; dvbdmxfeed->buffer_size = circular_buffer_size; - dvbdmxfeed->descramble = descramble; - if (dvbdmxfeed->descramble) { - up(&dvbdmx->mutex); - return -ENOSYS; - } - dvbdmxfeed->feed.sec.check_crc = check_crc; #ifdef NOBUFS diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h index 20275a2f6ec69..d149f2a96d09b 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.h +++ b/drivers/media/dvb/dvb-core/dvb_demux.h @@ -54,12 +54,9 @@ struct dvb_demux_filter { int index; int state; int type; - int pesto; - u16 handle; u16 hw_handle; struct timer_list timer; - int ts_state; }; @@ -83,11 +80,9 @@ struct dvb_demux_feed { u16 pid; u8 *buffer; int buffer_size; - int descramble; struct timespec timeout; struct dvb_demux_filter *filter; - int cb_length; int ts_type; enum dmx_ts_pes pes_type; @@ -98,7 +93,7 @@ struct dvb_demux_feed { u16 peslen; struct list_head list_head; - int index; /* a unique index for each feed (can be used as hardware pid filter index) */ + unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ }; struct dvb_demux { diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 33a357c48a19a..87935490bfb2f 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -903,7 +903,7 @@ static int dvb_net_feed_start(struct net_device *dev) return ret; } - ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 0, 1); + ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); if (ret<0) { printk("%s: could not set section feed\n", dev->name); @@ -955,9 +955,7 @@ static int dvb_net_feed_start(struct net_device *dev) priv->tsfeed->priv = (void *)dev; ret = priv->tsfeed->set(priv->tsfeed, priv->pid, TS_PACKET, DMX_TS_PES_OTHER, - 188 * 100, /* nr. of bytes delivered per callback */ 32768, /* circular buffer size */ - 0, /* descramble */ timeout); if (ret < 0) { -- GitLab From db574d7d6e38fe37bbb97e2b0a0363b5d2ffa203 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter <obi@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:26 -0700 Subject: [PATCH 119/563] [PATCH] dvb: core: dvb_demux: use INIT_LIST_HEAD Use INIT_LIST_HEAD for frontend_list. Signed-off-by: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-core/dvb_demux.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index b9cb671b938cc..528ca463a6dd9 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -1188,9 +1188,9 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dvbdemux->feed[i].state = DMX_STATE_FREE; dvbdemux->feed[i].index = i; } - dvbdemux->frontend_list.next= - dvbdemux->frontend_list.prev= - &dvbdemux->frontend_list; + + INIT_LIST_HEAD(&dvbdemux->frontend_list); + for (i=0; i<DMX_TS_PES_OTHER; i++) { dvbdemux->pesfilter[i] = NULL; dvbdemux->pids[i] = 0xffff; -- GitLab From dad4a73071532448f6cee29791476494a8eb3a58 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter <obi@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:26 -0700 Subject: [PATCH 120/563] [PATCH] dvb: core: dvb_demux formatting fixes Formatting fixes (Lindent + some handwork). Signed-off-by: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-core/dvb_demux.c | 469 ++++++++++++------------- drivers/media/dvb/dvb-core/dvb_demux.h | 107 +++--- 2 files changed, 283 insertions(+), 293 deletions(-) diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 528ca463a6dd9..dc476dda2b713 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -38,55 +38,52 @@ */ // #define DVB_DEMUX_SECTION_LOSS_LOG - /****************************************************************************** * static inlined helper functions ******************************************************************************/ - static inline u16 section_length(const u8 *buf) { - return 3+((buf[1]&0x0f)<<8)+buf[2]; + return 3 + ((buf[1] & 0x0f) << 8) + buf[2]; } - static inline u16 ts_pid(const u8 *buf) { - return ((buf[1]&0x1f)<<8)+buf[2]; + return ((buf[1] & 0x1f) << 8) + buf[2]; } - static inline u8 payload(const u8 *tsp) { - if (!(tsp[3] & 0x10)) // no payload? + if (!(tsp[3] & 0x10)) // no payload? return 0; - if (tsp[3] & 0x20) { // adaptation field? - if (tsp[4] > 183) // corrupted data? + + if (tsp[3] & 0x20) { // adaptation field? + if (tsp[4] > 183) // corrupted data? return 0; else - return 184-1-tsp[4]; + return 184 - 1 - tsp[4]; } + return 184; } - -static u32 dvb_dmx_crc32 (struct dvb_demux_feed *f, const u8 *src, size_t len) +static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len) { - return (f->feed.sec.crc_val = crc32_be (f->feed.sec.crc_val, src, len)); + return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len)); } - -static void dvb_dmx_memcopy (struct dvb_demux_feed *f, u8 *d, const u8 *s, size_t len) +static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s, + size_t len) { - memcpy (d, s, len); + memcpy(d, s, len); } - /****************************************************************************** * Software filter functions ******************************************************************************/ -static inline int dvb_dmx_swfilter_payload (struct dvb_demux_feed *feed, const u8 *buf) +static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, + const u8 *buf) { int count = payload(buf); int p; @@ -96,32 +93,31 @@ static inline int dvb_dmx_swfilter_payload (struct dvb_demux_feed *feed, const u if (count == 0) return -1; - p = 188-count; + p = 188 - count; /* - cc=buf[3]&0x0f; - ccok=((dvbdmxfeed->cc+1)&0x0f)==cc ? 1 : 0; - dvbdmxfeed->cc=cc; + cc = buf[3] & 0x0f; + ccok = ((feed->cc + 1) & 0x0f) == cc; + feed->cc = cc; if (!ccok) printk("missed packet!\n"); */ - if (buf[1] & 0x40) // PUSI ? + if (buf[1] & 0x40) // PUSI ? feed->peslen = 0xfffa; feed->peslen += count; - return feed->cb.ts (&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); + return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); } - -static int dvb_dmx_swfilter_sectionfilter (struct dvb_demux_feed *feed, - struct dvb_demux_filter *f) +static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, + struct dvb_demux_filter *f) { u8 neq = 0; int i; - for (i=0; i<DVB_DEMUX_MASK_MAX; i++) { + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i]; if (f->maskandmode[i] & xor) @@ -133,12 +129,11 @@ static int dvb_dmx_swfilter_sectionfilter (struct dvb_demux_feed *feed, if (f->doneq && !neq) return 0; - return feed->cb.sec (feed->feed.sec.secbuf, feed->feed.sec.seclen, - NULL, 0, &f->filter, DMX_OK); + return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, + NULL, 0, &f->filter, DMX_OK); } - -static inline int dvb_dmx_swfilter_section_feed (struct dvb_demux_feed *feed) +static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct dvb_demux_filter *f = feed->filter; @@ -168,26 +163,24 @@ static inline int dvb_dmx_swfilter_section_feed (struct dvb_demux_feed *feed) return 0; } - static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) { struct dmx_section_feed *sec = &feed->feed.sec; #ifdef DVB_DEMUX_SECTION_LOSS_LOG - if(sec->secbufp < sec->tsfeedp) - { + if (sec->secbufp < sec->tsfeedp) { int i, n = sec->tsfeedp - sec->secbufp; - /* section padding is done with 0xff bytes entirely. - ** due to speed reasons, we won't check all of them - ** but just first and last - */ - if(sec->secbuf[0] != 0xff || sec->secbuf[n-1] != 0xff) - { + /* + * Section padding is done with 0xff bytes entirely. + * Due to speed reasons, we won't check all of them + * but just first and last. + */ + if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { printk("dvb_demux.c section ts padding loss: %d/%d\n", n, sec->tsfeedp); printk("dvb_demux.c pad data:"); - for(i = 0; i < n; i++) + for (i = 0; i < n; i++) printk(" %02x", sec->secbuf[i]); printk("\n"); } @@ -199,82 +192,81 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) } /* -** Losless Section Demux 1.4.1 by Emard -** Valsecchi Patrick: -** - middle of section A (no PUSI) -** - end of section A and start of section B -** (with PUSI pointing to the start of the second section) -** -** In this case, without feed->pusi_seen you'll receive a garbage section -** consisting of the end of section A. Basically because tsfeedp -** is incemented and the use=0 condition is not raised -** when the second packet arrives. -** -** Fix: -** when demux is started, let feed->pusi_seen = 0 to -** prevent initial feeding of garbage from the end of -** previous section. When you for the first time see PUSI=1 -** then set feed->pusi_seen = 1 -*/ -static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const u8 *buf, u8 len) + * Losless Section Demux 1.4.1 by Emard + * Valsecchi Patrick: + * - middle of section A (no PUSI) + * - end of section A and start of section B + * (with PUSI pointing to the start of the second section) + * + * In this case, without feed->pusi_seen you'll receive a garbage section + * consisting of the end of section A. Basically because tsfeedp + * is incemented and the use=0 condition is not raised + * when the second packet arrives. + * + * Fix: + * when demux is started, let feed->pusi_seen = 0 to + * prevent initial feeding of garbage from the end of + * previous section. When you for the first time see PUSI=1 + * then set feed->pusi_seen = 1 + */ +static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, + const u8 *buf, u8 len) { struct dvb_demux *demux = feed->demux; struct dmx_section_feed *sec = &feed->feed.sec; u16 limit, seclen, n; - if(sec->tsfeedp >= DMX_MAX_SECFEED_SIZE) + if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE) return 0; - if(sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) - { + if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { #ifdef DVB_DEMUX_SECTION_LOSS_LOG printk("dvb_demux.c section buffer full loss: %d/%d\n", - sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, DMX_MAX_SECFEED_SIZE); + sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, + DMX_MAX_SECFEED_SIZE); #endif len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; } - if(len <= 0) + if (len <= 0) return 0; demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len); sec->tsfeedp += len; - /* ----------------------------------------------------- - ** Dump all the sections we can find in the data (Emard) - */ - + /* + * Dump all the sections we can find in the data (Emard) + */ limit = sec->tsfeedp; - if(limit > DMX_MAX_SECFEED_SIZE) - return -1; /* internal error should never happen */ + if (limit > DMX_MAX_SECFEED_SIZE) + return -1; /* internal error should never happen */ /* to be sure always set secbuf */ sec->secbuf = sec->secbuf_base + sec->secbufp; - for(n = 0; sec->secbufp + 2 < limit; n++) - { + for (n = 0; sec->secbufp + 2 < limit; n++) { seclen = section_length(sec->secbuf); - if(seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE - || seclen + sec->secbufp > limit) + if (seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE + || seclen + sec->secbufp > limit) return 0; sec->seclen = seclen; sec->crc_val = ~0; /* dump [secbuf .. secbuf+seclen) */ - if(feed->pusi_seen) + if (feed->pusi_seen) dvb_dmx_swfilter_section_feed(feed); #ifdef DVB_DEMUX_SECTION_LOSS_LOG else printk("dvb_demux.c pusi not seen, discarding section data\n"); #endif - sec->secbufp += seclen; /* secbufp and secbuf moving together is */ - sec->secbuf += seclen; /* redundand but saves pointer arithmetic */ + sec->secbufp += seclen; /* secbufp and secbuf moving together is */ + sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ } return 0; } - -static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) +static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, + const u8 *buf) { u8 p, count; int ccok, dc_i = 0; @@ -282,10 +274,10 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 count = payload(buf); - if (count == 0) /* count == 0 if no payload or out of range */ + if (count == 0) /* count == 0 if no payload or out of range */ return -1; - p = 188 - count; /* payload start */ + p = 188 - count; /* payload start */ cc = buf[3] & 0x0f; ccok = ((feed->cc + 1) & 0x0f) == cc; @@ -299,51 +291,53 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 if (!ccok || dc_i) { #ifdef DVB_DEMUX_SECTION_LOSS_LOG - printk("dvb_demux.c discontinuity detected %d bytes lost\n", count); - /* those bytes under sume circumstances will again be reported - ** in the following dvb_dmx_swfilter_section_new - */ + printk("dvb_demux.c discontinuity detected %d bytes lost\n", + count); + /* + * those bytes under sume circumstances will again be reported + * in the following dvb_dmx_swfilter_section_new + */ #endif - /* Discontinuity detected. Reset pusi_seen = 0 to - ** stop feeding of suspicious data until next PUSI=1 arrives - */ + /* + * Discontinuity detected. Reset pusi_seen = 0 to + * stop feeding of suspicious data until next PUSI=1 arrives + */ feed->pusi_seen = 0; dvb_dmx_swfilter_section_new(feed); } if (buf[1] & 0x40) { - // PUSI=1 (is set), section boundary is here + /* PUSI=1 (is set), section boundary is here */ if (count > 1 && buf[p] < count) { - const u8 *before = buf+p+1; + const u8 *before = &buf[p + 1]; u8 before_len = buf[p]; - const u8 *after = before+before_len; - u8 after_len = count-1-before_len; + const u8 *after = &before[before_len]; + u8 after_len = count - 1 - before_len; - dvb_dmx_swfilter_section_copy_dump(feed, before, before_len); + dvb_dmx_swfilter_section_copy_dump(feed, before, + before_len); /* before start of new section, set pusi_seen = 1 */ feed->pusi_seen = 1; dvb_dmx_swfilter_section_new(feed); - dvb_dmx_swfilter_section_copy_dump(feed, after, after_len); + dvb_dmx_swfilter_section_copy_dump(feed, after, + after_len); } #ifdef DVB_DEMUX_SECTION_LOSS_LOG - else - if (count > 0) - printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); + else if (count > 0) + printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); #endif } else { - // PUSI=0 (is not set), no section boundary - const u8 *entire = buf+p; - u8 entire_len = count; - - dvb_dmx_swfilter_section_copy_dump(feed, entire, entire_len); + /* PUSI=0 (is not set), no section boundary */ + dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count); } + return 0; } - -static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, const u8 *buf) +static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, + const u8 *buf) { - switch(feed->type) { + switch (feed->type) { case DMX_TYPE_TS: if (!feed->feed.ts.is_filtering) break; @@ -351,7 +345,8 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, con if (feed->ts_type & TS_PAYLOAD_ONLY) dvb_dmx_swfilter_payload(feed, buf); else - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, + DMX_OK); } if (feed->ts_type & TS_DECODER) if (feed->demux->write_to_decoder) @@ -362,7 +357,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, con if (!feed->feed.sec.is_filtering) break; if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) - feed->feed.sec.seclen = feed->feed.sec.secbufp=0; + feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; break; default: @@ -378,7 +373,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, con static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) { struct dvb_demux_feed *feed; - struct list_head *pos, *head=&demux->feed_list; + struct list_head *pos, *head = &demux->feed_list; u16 pid = ts_pid(buf); int dvr_done = 0; @@ -404,21 +399,21 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) } } -void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count) +void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, + size_t count) { spin_lock(&demux->lock); while (count--) { - if(buf[0] == 0x47) { - dvb_dmx_swfilter_packet(demux, buf); - } + if (buf[0] == 0x47) + dvb_dmx_swfilter_packet(demux, buf); buf += 188; } spin_unlock(&demux->lock); } -EXPORT_SYMBOL(dvb_dmx_swfilter_packets); +EXPORT_SYMBOL(dvb_dmx_swfilter_packets); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) { @@ -426,8 +421,10 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) spin_lock(&demux->lock); - if ((i = demux->tsbufp)) { - if (count < (j=188-i)) { + if (demux->tsbufp) { + i = demux->tsbufp; + j = 188 - i; + if (count < j) { memcpy(&demux->tsbuf[i], buf, count); demux->tsbufp += count; goto bailout; @@ -441,13 +438,13 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) while (p < count) { if (buf[p] == 0x47) { - if (count-p >= 188) { - dvb_dmx_swfilter_packet(demux, buf+p); + if (count - p >= 188) { + dvb_dmx_swfilter_packet(demux, &buf[p]); p += 188; } else { - i = count-p; - memcpy(demux->tsbuf, buf+p, i); - demux->tsbufp=i; + i = count - p; + memcpy(demux->tsbuf, &buf[p], i); + demux->tsbufp = i; goto bailout; } } else @@ -457,24 +454,29 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) bailout: spin_unlock(&demux->lock); } + EXPORT_SYMBOL(dvb_dmx_swfilter); void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) { - int p = 0,i, j; + int p = 0, i, j; u8 tmppack[188]; + spin_lock(&demux->lock); - if ((i = demux->tsbufp)) { - if (count < (j=204-i)) { + if (demux->tsbufp) { + i = demux->tsbufp; + j = 204 - i; + if (count < j) { memcpy(&demux->tsbuf[i], buf, count); demux->tsbufp += count; goto bailout; } memcpy(&demux->tsbuf[i], buf, j); - if ((demux->tsbuf[0] == 0x47)|(demux->tsbuf[0]==0xB8)) { + if ((demux->tsbuf[0] == 0x47) | (demux->tsbuf[0] == 0xB8)) { memcpy(tmppack, demux->tsbuf, 188); - if (tmppack[0] == 0xB8) tmppack[0] = 0x47; + if (tmppack[0] == 0xB8) + tmppack[0] = 0x47; dvb_dmx_swfilter_packet(demux, tmppack); } demux->tsbufp = 0; @@ -482,16 +484,17 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) } while (p < count) { - if ((buf[p] == 0x47)|(buf[p] == 0xB8)) { - if (count-p >= 204) { - memcpy(tmppack, buf+p, 188); - if (tmppack[0] == 0xB8) tmppack[0] = 0x47; + if ((buf[p] == 0x47) | (buf[p] == 0xB8)) { + if (count - p >= 204) { + memcpy(tmppack, &buf[p], 188); + if (tmppack[0] == 0xB8) + tmppack[0] = 0x47; dvb_dmx_swfilter_packet(demux, tmppack); p += 204; } else { - i = count-p; - memcpy(demux->tsbuf, buf+p, i); - demux->tsbufp=i; + i = count - p; + memcpy(demux->tsbuf, &buf[p], i); + demux->tsbufp = i; goto bailout; } } else { @@ -502,14 +505,14 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) bailout: spin_unlock(&demux->lock); } -EXPORT_SYMBOL(dvb_dmx_swfilter_204); +EXPORT_SYMBOL(dvb_dmx_swfilter_204); -static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux) +static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) { int i; - for (i=0; i<demux->filternum; i++) + for (i = 0; i < demux->filternum; i++) if (demux->filter[i].state == DMX_STATE_FREE) break; @@ -521,11 +524,11 @@ static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux) return &demux->filter[i]; } -static struct dvb_demux_feed * dvb_dmx_feed_alloc(struct dvb_demux *demux) +static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux) { int i; - for (i=0; i<demux->feednum; i++) + for (i = 0; i < demux->feednum; i++) if (demux->feed[i].state == DMX_STATE_FREE) break; @@ -553,7 +556,7 @@ static void dvb_demux_feed_add(struct dvb_demux_feed *feed) spin_lock_irq(&feed->demux->lock); if (dvb_demux_feed_find(feed)) { printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n", - __FUNCTION__, feed->type, feed->state, feed->pid); + __FUNCTION__, feed->type, feed->state, feed->pid); goto out; } @@ -567,7 +570,7 @@ static void dvb_demux_feed_del(struct dvb_demux_feed *feed) spin_lock_irq(&feed->demux->lock); if (!(dvb_demux_feed_find(feed))) { printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n", - __FUNCTION__, feed->type, feed->state, feed->pid); + __FUNCTION__, feed->type, feed->state, feed->pid); goto out; } @@ -576,17 +579,17 @@ static void dvb_demux_feed_del(struct dvb_demux_feed *feed) spin_unlock_irq(&feed->demux->lock); } -static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, - enum dmx_ts_pes pes_type, size_t circular_buffer_size, - struct timespec timeout) +static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, + enum dmx_ts_pes pes_type, + size_t circular_buffer_size, struct timespec timeout) { - struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; if (pid > DMX_MAX_PID) return -EINVAL; - if (down_interruptible (&demux->mutex)) + if (down_interruptible(&demux->mutex)) return -ERESTARTSYS; if (ts_type & TS_DECODER) { @@ -615,7 +618,7 @@ static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, if (feed->buffer_size) { #ifdef NOBUFS - feed->buffer=NULL; + feed->buffer = NULL; #else feed->buffer = vmalloc(feed->buffer_size); if (!feed->buffer) { @@ -631,14 +634,13 @@ static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, return 0; } - -static int dmx_ts_feed_start_filtering(struct dmx_ts_feed* ts_feed) +static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) { - struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; int ret; - if (down_interruptible (&demux->mutex)) + if (down_interruptible(&demux->mutex)) return -ERESTARTSYS; if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { @@ -665,13 +667,13 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed* ts_feed) return 0; } -static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed* ts_feed) +static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed) { - struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; int ret; - if (down_interruptible (&demux->mutex)) + if (down_interruptible(&demux->mutex)) return -ERESTARTSYS; if (feed->state < DMX_STATE_GO) { @@ -695,13 +697,14 @@ static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed* ts_feed) return ret; } -static int dvbdmx_allocate_ts_feed (struct dmx_demux *dmx, struct dmx_ts_feed **ts_feed, - dmx_ts_cb callback) +static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, + struct dmx_ts_feed **ts_feed, + dmx_ts_cb callback) { - struct dvb_demux *demux = (struct dvb_demux *) dmx; + struct dvb_demux *demux = (struct dvb_demux *)dmx; struct dvb_demux_feed *feed; - if (down_interruptible (&demux->mutex)) + if (down_interruptible(&demux->mutex)) return -ERESTARTSYS; if (!(feed = dvb_dmx_feed_alloc(demux))) { @@ -724,7 +727,6 @@ static int dvbdmx_allocate_ts_feed (struct dmx_demux *dmx, struct dmx_ts_feed ** (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering; (*ts_feed)->set = dmx_ts_feed_set; - if (!(feed->filter = dvb_dmx_filter_alloc(demux))) { feed->state = DMX_STATE_FREE; up(&demux->mutex); @@ -740,22 +742,22 @@ static int dvbdmx_allocate_ts_feed (struct dmx_demux *dmx, struct dmx_ts_feed ** return 0; } -static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, struct dmx_ts_feed *ts_feed) +static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, + struct dmx_ts_feed *ts_feed) { - struct dvb_demux *demux = (struct dvb_demux *) dmx; - struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed; + struct dvb_demux *demux = (struct dvb_demux *)dmx; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; - if (down_interruptible (&demux->mutex)) + if (down_interruptible(&demux->mutex)) return -ERESTARTSYS; if (feed->state == DMX_STATE_FREE) { up(&demux->mutex); return -EINVAL; } - #ifndef NOBUFS vfree(feed->buffer); - feed->buffer=0; + feed->buffer = NULL; #endif feed->state = DMX_STATE_FREE; @@ -772,19 +774,18 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, struct dmx_ts_feed *ts_ return 0; } - /****************************************************************************** * dmx_section_feed API calls ******************************************************************************/ -static int dmx_section_feed_allocate_filter(struct dmx_section_feed* feed, - struct dmx_section_filter** filter) +static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed, + struct dmx_section_filter **filter) { - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdemux = dvbdmxfeed->demux; struct dvb_demux_filter *dvbdmxfilter; - if (down_interruptible (&dvbdemux->mutex)) + if (down_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux); @@ -808,18 +809,17 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed* feed, return 0; } - -static int dmx_section_feed_set(struct dmx_section_feed* feed, - u16 pid, size_t circular_buffer_size, - int check_crc) +static int dmx_section_feed_set(struct dmx_section_feed *feed, + u16 pid, size_t circular_buffer_size, + int check_crc) { - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; if (pid > 0x1fff) return -EINVAL; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; dvb_demux_feed_add(dvbdmxfeed); @@ -831,7 +831,7 @@ static int dmx_section_feed_set(struct dmx_section_feed* feed, #ifdef NOBUFS dvbdmxfeed->buffer = NULL; #else - dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size); + dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size); if (!dvbdmxfeed->buffer) { up(&dvbdmx->mutex); return -ENOMEM; @@ -843,7 +843,6 @@ static int dmx_section_feed_set(struct dmx_section_feed* feed, return 0; } - static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) { int i; @@ -851,12 +850,12 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) struct dmx_section_filter *sf; u8 mask, mode, doneq; - if (!(f=dvbdmxfeed->filter)) + if (!(f = dvbdmxfeed->filter)) return; do { sf = &f->filter; doneq = 0; - for (i=0; i<DVB_DEMUX_MASK_MAX; i++) { + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { mode = sf->filter_mode[i]; mask = sf->filter_mask[i]; f->maskandmode[i] = mask & mode; @@ -866,14 +865,13 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) } while ((f = f->next)); } - static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) { - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; int ret; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; if (feed->is_filtering) { @@ -912,14 +910,13 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) return 0; } - -static int dmx_section_feed_stop_filtering(struct dmx_section_feed* feed) +static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed) { - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; int ret; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; if (!dvbdmx->stop_feed) { @@ -938,15 +935,14 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed* feed) return ret; } - static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, - struct dmx_section_filter* filter) + struct dmx_section_filter *filter) { - struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *) filter, *f; - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; + struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; if (dvbdmxfilter->feed != dvbdmxfeed) { @@ -963,7 +959,7 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, if (f == dvbdmxfilter) { dvbdmxfeed->filter = dvbdmxfilter->next; } else { - while(f->next != dvbdmxfilter) + while (f->next != dvbdmxfilter) f = f->next; f->next = f->next->next; } @@ -978,10 +974,10 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, struct dmx_section_feed **feed, dmx_section_cb callback) { - struct dvb_demux *dvbdmx = (struct dvb_demux *) demux; + struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; struct dvb_demux_feed *dvbdmxfeed; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) { @@ -999,7 +995,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, dvbdmxfeed->filter = NULL; dvbdmxfeed->buffer = NULL; - (*feed)=&dvbdmxfeed->feed.sec; + (*feed) = &dvbdmxfeed->feed.sec; (*feed)->is_filtering = 0; (*feed)->parent = demux; (*feed)->priv = NULL; @@ -1017,21 +1013,21 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, static int dvbdmx_release_section_feed(struct dmx_demux *demux, struct dmx_section_feed *feed) { - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; - struct dvb_demux *dvbdmx = (struct dvb_demux *) demux; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; - if (dvbdmxfeed->state==DMX_STATE_FREE) { + if (dvbdmxfeed->state == DMX_STATE_FREE) { up(&dvbdmx->mutex); return -EINVAL; } #ifndef NOBUFS vfree(dvbdmxfeed->buffer); - dvbdmxfeed->buffer=0; + dvbdmxfeed->buffer = NULL; #endif - dvbdmxfeed->state=DMX_STATE_FREE; + dvbdmxfeed->state = DMX_STATE_FREE; dvb_demux_feed_del(dvbdmxfeed); @@ -1041,14 +1037,13 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux, return 0; } - /****************************************************************************** * dvb_demux kernel data API calls ******************************************************************************/ static int dvbdmx_open(struct dmx_demux *demux) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; if (dvbdemux->users >= MAX_DVB_DEMUX_USERS) return -EUSERS; @@ -1057,10 +1052,9 @@ static int dvbdmx_open(struct dmx_demux *demux) return 0; } - static int dvbdmx_close(struct dmx_demux *demux) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; if (dvbdemux->users == 0) return -ENODEV; @@ -1070,15 +1064,14 @@ static int dvbdmx_close(struct dmx_demux *demux) return 0; } - static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count) { - struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE)) return -EINVAL; - if (down_interruptible (&dvbdemux->mutex)) + if (down_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; dvb_dmx_swfilter(dvbdemux, buf, count); up(&dvbdemux->mutex); @@ -1088,10 +1081,10 @@ static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count) return count; } - -static int dvbdmx_add_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend) +static int dvbdmx_add_frontend(struct dmx_demux *demux, + struct dmx_frontend *frontend) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; struct list_head *head = &dvbdemux->frontend_list; list_add(&(frontend->connectivity_list), head); @@ -1099,13 +1092,13 @@ static int dvbdmx_add_frontend(struct dmx_demux *demux, struct dmx_frontend *fro return 0; } - -static int dvbdmx_remove_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend) +static int dvbdmx_remove_frontend(struct dmx_demux *demux, + struct dmx_frontend *frontend) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; struct list_head *pos, *n, *head = &dvbdemux->frontend_list; - list_for_each_safe (pos, n, head) { + list_for_each_safe(pos, n, head) { if (DMX_FE_ENTRY(pos) == frontend) { list_del(pos); return 0; @@ -1115,25 +1108,25 @@ static int dvbdmx_remove_frontend(struct dmx_demux *demux, struct dmx_frontend * return -ENODEV; } - -static struct list_head * dvbdmx_get_frontends(struct dmx_demux *demux) +static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; if (list_empty(&dvbdemux->frontend_list)) return NULL; + return &dvbdemux->frontend_list; } - -static int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend) +static int dvbdmx_connect_frontend(struct dmx_demux *demux, + struct dmx_frontend *frontend) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; if (demux->frontend) return -EINVAL; - if (down_interruptible (&dvbdemux->mutex)) + if (down_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; demux->frontend = frontend; @@ -1141,12 +1134,11 @@ static int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend return 0; } - static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - if (down_interruptible (&dvbdemux->mutex)) + if (down_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; demux->frontend = NULL; @@ -1154,44 +1146,42 @@ static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) return 0; } - -static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids) +static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - memcpy(pids, dvbdemux->pids, 5*sizeof(u16)); + memcpy(pids, dvbdemux->pids, 5 * sizeof(u16)); return 0; } - int dvb_dmx_init(struct dvb_demux *dvbdemux) { int i; struct dmx_demux *dmx = &dvbdemux->dmx; dvbdemux->users = 0; - dvbdemux->filter = vmalloc(dvbdemux->filternum*sizeof(struct dvb_demux_filter)); + dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); if (!dvbdemux->filter) return -ENOMEM; - dvbdemux->feed = vmalloc(dvbdemux->feednum*sizeof(struct dvb_demux_feed)); + dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed)); if (!dvbdemux->feed) { vfree(dvbdemux->filter); return -ENOMEM; } - for (i=0; i<dvbdemux->filternum; i++) { + for (i = 0; i < dvbdemux->filternum; i++) { dvbdemux->filter[i].state = DMX_STATE_FREE; dvbdemux->filter[i].index = i; } - for (i=0; i<dvbdemux->feednum; i++) { + for (i = 0; i < dvbdemux->feednum; i++) { dvbdemux->feed[i].state = DMX_STATE_FREE; dvbdemux->feed[i].index = i; } INIT_LIST_HEAD(&dvbdemux->frontend_list); - for (i=0; i<DMX_TS_PES_OTHER; i++) { + for (i = 0; i < DMX_TS_PES_OTHER; i++) { dvbdemux->pesfilter[i] = NULL; dvbdemux->pids[i] = 0xffff; } @@ -1205,11 +1195,11 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) if (!dvbdemux->check_crc32) dvbdemux->check_crc32 = dvb_dmx_crc32; - if (!dvbdemux->memcopy) - dvbdemux->memcopy = dvb_dmx_memcopy; + if (!dvbdemux->memcopy) + dvbdemux->memcopy = dvb_dmx_memcopy; dmx->frontend = NULL; - dmx->priv = (void *) dvbdemux; + dmx->priv = dvbdemux; dmx->open = dvbdmx_open; dmx->close = dvbdmx_close; dmx->write = dvbdmx_write; @@ -1230,12 +1220,13 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) return 0; } -EXPORT_SYMBOL(dvb_dmx_init); +EXPORT_SYMBOL(dvb_dmx_init); void dvb_dmx_release(struct dvb_demux *dvbdemux) { vfree(dvbdemux->filter); vfree(dvbdemux->feed); } + EXPORT_SYMBOL(dvb_dmx_release); diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h index d149f2a96d09b..0cc888339d52e 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.h +++ b/drivers/media/dvb/dvb-core/dvb_demux.h @@ -20,7 +20,6 @@ * */ - #ifndef _DVB_DEMUX_H_ #define _DVB_DEMUX_H_ @@ -44,98 +43,98 @@ #define DVB_DEMUX_MASK_MAX 18 struct dvb_demux_filter { - struct dmx_section_filter filter; - u8 maskandmode [DMX_MAX_FILTER_SIZE]; - u8 maskandnotmode [DMX_MAX_FILTER_SIZE]; + struct dmx_section_filter filter; + u8 maskandmode[DMX_MAX_FILTER_SIZE]; + u8 maskandnotmode[DMX_MAX_FILTER_SIZE]; int doneq; - struct dvb_demux_filter *next; - struct dvb_demux_feed *feed; - int index; - int state; - int type; + struct dvb_demux_filter *next; + struct dvb_demux_feed *feed; + int index; + int state; + int type; - u16 hw_handle; - struct timer_list timer; + u16 hw_handle; + struct timer_list timer; }; - #define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head) struct dvb_demux_feed { - union { - struct dmx_ts_feed ts; - struct dmx_section_feed sec; + union { + struct dmx_ts_feed ts; + struct dmx_section_feed sec; } feed; - union { - dmx_ts_cb ts; - dmx_section_cb sec; + union { + dmx_ts_cb ts; + dmx_section_cb sec; } cb; - struct dvb_demux *demux; + struct dvb_demux *demux; void *priv; - int type; - int state; - u16 pid; - u8 *buffer; - int buffer_size; + int type; + int state; + u16 pid; + u8 *buffer; + int buffer_size; - struct timespec timeout; - struct dvb_demux_filter *filter; + struct timespec timeout; + struct dvb_demux_filter *filter; - int ts_type; - enum dmx_ts_pes pes_type; + int ts_type; + enum dmx_ts_pes pes_type; - int cc; - int pusi_seen; /* prevents feeding of garbage from previous section */ + int cc; + int pusi_seen; /* prevents feeding of garbage from previous section */ - u16 peslen; + u16 peslen; struct list_head list_head; - unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ + unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ }; struct dvb_demux { - struct dmx_demux dmx; - void *priv; - int filternum; - int feednum; - int (*start_feed) (struct dvb_demux_feed *feed); - int (*stop_feed) (struct dvb_demux_feed *feed); - int (*write_to_decoder) (struct dvb_demux_feed *feed, + struct dmx_demux dmx; + void *priv; + int filternum; + int feednum; + int (*start_feed)(struct dvb_demux_feed *feed); + int (*stop_feed)(struct dvb_demux_feed *feed); + int (*write_to_decoder)(struct dvb_demux_feed *feed, const u8 *buf, size_t len); - u32 (*check_crc32) (struct dvb_demux_feed *feed, + u32 (*check_crc32)(struct dvb_demux_feed *feed, const u8 *buf, size_t len); - void (*memcopy) (struct dvb_demux_feed *feed, u8 *dst, + void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst, const u8 *src, size_t len); - int users; + int users; #define MAX_DVB_DEMUX_USERS 10 - struct dvb_demux_filter *filter; - struct dvb_demux_feed *feed; + struct dvb_demux_filter *filter; + struct dvb_demux_feed *feed; - struct list_head frontend_list; + struct list_head frontend_list; - struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER]; - u16 pids[DMX_TS_PES_OTHER]; - int playing; - int recording; + struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER]; + u16 pids[DMX_TS_PES_OTHER]; + int playing; + int recording; #define DMX_MAX_PID 0x2000 struct list_head feed_list; - u8 tsbuf[204]; - int tsbufp; + u8 tsbuf[204]; + int tsbufp; struct semaphore mutex; spinlock_t lock; }; - int dvb_dmx_init(struct dvb_demux *dvbdemux); void dvb_dmx_release(struct dvb_demux *dvbdemux); -void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, size_t count); +void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, + size_t count); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); -void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count); +void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, + size_t count); #endif /* _DVB_DEMUX_H_ */ -- GitLab From 50b447d5b70dc4021ae3b4eaf8ce98932f61a413 Mon Sep 17 00:00:00 2001 From: Dominique Dumont <domi.dumont@free.fr> Date: Fri, 9 Sep 2005 13:02:27 -0700 Subject: [PATCH 121/563] [PATCH] dvb: core: CI timeout fix Patch from Dominique Dumont to get the SCM Red Viaccess CAM working with the budget-ci. Signed-off-by: Dominique Dumont <domi.dumont@free.fr> Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 0eb9aa711fb03..88757e2634e5c 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -47,7 +47,7 @@ MODULE_PARM_DESC(cam_debug, "enable verbose debug messages"); #define dprintk if (dvb_ca_en50221_debug) printk -#define INIT_TIMEOUT_SECS 5 +#define INIT_TIMEOUT_SECS 10 #define HOST_LINK_BUF_SIZE 0x200 -- GitLab From 4ff4ac1beae58a2fea7ec2ad43d6c3b60d90ec61 Mon Sep 17 00:00:00 2001 From: Barry Scott <barry.scott@onelan.co.uk> Date: Fri, 9 Sep 2005 13:02:29 -0700 Subject: [PATCH 122/563] [PATCH] dvb: frontend: mt352: fix signal strength reading Fix two problems with the signal strength value in the mt352.c frontend: 1. the 4 most significant bits are zeroed - shift and mask wrong way round 2. need to align the 12 bits from the registers at the top of the 16 bit returned value - otherwise the range is not 0 to 0xffff its 0xf000 to 0xffff Signed-off-by: Barry Scott <barry.scott@onelan.co.uk> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/frontends/mt352.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index d32dc4de9e7f1..cc1bc0edd65e7 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -462,9 +462,11 @@ static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength) { struct mt352_state* state = fe->demodulator_priv; - u16 signal = ((mt352_read_register(state, AGC_GAIN_1) << 8) & 0x0f) | - (mt352_read_register(state, AGC_GAIN_0)); + /* align the 12 bit AGC gain with the most significant bits */ + u16 signal = ((mt352_read_register(state, AGC_GAIN_1) & 0x0f) << 12) | + (mt352_read_register(state, AGC_GAIN_0) << 4); + /* inverse of gain is signal strength */ *strength = ~signal; return 0; } -- GitLab From cfbfce1566f11c0dbad8a16173f0448b0c78cecb Mon Sep 17 00:00:00 2001 From: Andreas Oberritter <obi@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:30 -0700 Subject: [PATCH 123/563] [PATCH] dvb: frontend: stv0299: pass i2c bus to pll callback Pass a pointer to the i2c bus to the pll callbacks (stv0299 only). It was not possible to tell which i2c bus should be used if an adapter has multiple frontends on multiple i2c buses. Signed-off-by: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 5 ++--- drivers/media/dvb/frontends/stv0299.c | 6 +++--- drivers/media/dvb/frontends/stv0299.h | 4 ++-- drivers/media/dvb/ttpci/av7110.c | 10 ++++------ drivers/media/dvb/ttpci/budget-av.c | 4 ++-- drivers/media/dvb/ttpci/budget-ci.c | 9 ++++----- drivers/media/dvb/ttpci/budget-patch.c | 5 ++--- drivers/media/dvb/ttpci/budget.c | 5 ++--- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 4 ++-- 9 files changed, 23 insertions(+), 29 deletions(-) diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 0410cc96a48e2..a36bec3a2beaa 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -164,12 +164,11 @@ static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, return 0; } -static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { u8 buf[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - struct flexcop_device *fc = fe->dvb->priv; div = params->frequency / 125; @@ -180,7 +179,7 @@ static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_fronten if (params->frequency < 1500000) buf[3] |= 0x10; - if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index cfa3928bb487b..db66d417df382 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -481,7 +481,7 @@ static int stv0299_init (struct dvb_frontend* fe) if (state->config->pll_init) { stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_init(fe); + state->config->pll_init(fe, state->i2c); stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ } @@ -603,7 +603,7 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par } else { /* A "normal" tune is requested */ stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_set(fe, p); + state->config->pll_set(fe, state->i2c, p); stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ stv0299_writeregI(state, 0x32, 0x80); @@ -615,7 +615,7 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par } } else { stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_set(fe, p); + state->config->pll_set(fe, state->i2c, p); stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ stv0299_set_FEC (state, p->u.qpsk.fec_inner); diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h index 79457a80a11fb..d0c4484861e19 100644 --- a/drivers/media/dvb/frontends/stv0299.h +++ b/drivers/media/dvb/frontends/stv0299.h @@ -92,8 +92,8 @@ struct stv0299_config int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio); /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*pll_init)(struct dvb_frontend *fe, struct i2c_adapter *i2c); + int (*pll_set)(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params); }; extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data); diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index e4c6e87f6c5d6..c91cf8958b38c 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -1668,9 +1668,8 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { - struct av7110* av7110 = (struct av7110*) fe->dvb->priv; int ret; u8 data[4]; u32 div; @@ -1687,7 +1686,7 @@ static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param if (params->frequency > 1530000) data[3] = 0xc0; - ret = i2c_transfer(&av7110->i2c_adap, &msg, 1); + ret = i2c_transfer(i2c, &msg, 1); if (ret != 1) return -EIO; return 0; @@ -1751,9 +1750,8 @@ static u8 alps_bsbe1_inittab[] = { 0xff, 0xff }; -static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { - struct av7110* av7110 = (struct av7110*) fe->dvb->priv; int ret; u8 data[4]; u32 div; @@ -1768,7 +1766,7 @@ static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param data[2] = 0x80 | ((div & 0x18000) >> 10) | 4; data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4; - ret = i2c_transfer(&av7110->i2c_adap, &msg, 1); + ret = i2c_transfer(i2c, &msg, 1); return (ret != 1) ? -EIO : 0; } diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 9746d2bb916f3..311be50b2fce5 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -453,9 +453,9 @@ static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 sra } static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct dvb_frontend_parameters *params) { - struct budget_av *budget_av = (struct budget_av *) fe->dvb->priv; u32 div; u8 buf[4]; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; @@ -481,7 +481,7 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe, else if (params->frequency < 2150000) buf[3] |= 0xC0; - if (i2c_transfer(&budget_av->budget.i2c_adap, &msg, 1) != 1) + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index a1267054bc018..88f27a5321630 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -548,9 +548,8 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params) { - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u8 buf[4]; u32 div; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; @@ -567,7 +566,7 @@ static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_param if (params->frequency > 1530000) buf[3] = 0xc0; - if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } @@ -669,9 +668,9 @@ static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, } static int philips_su1278_tt_pll_set(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct dvb_frontend_parameters *params) { - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u32 div; u8 buf[4]; struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; @@ -697,7 +696,7 @@ static int philips_su1278_tt_pll_set(struct dvb_frontend *fe, else if (params->frequency < 2150000) buf[3] |= 0xC0; - if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 8142e26b47f5d..b1f21ef0e3b39 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -353,9 +353,8 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { - struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; u8 data[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; @@ -370,7 +369,7 @@ static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param if (params->frequency > 1530000) data[3] = 0xc0; - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 9961917e8a7fd..5552ef5019966 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -332,9 +332,8 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { - struct budget* budget = (struct budget*) fe->dvb->priv; u8 data[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; @@ -349,7 +348,7 @@ static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param if (params->frequency > 1530000) data[3] = 0xc0; - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 7daf7b1598a0d..c1acd4bb34992 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1299,7 +1299,7 @@ static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 return 0; } -static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params) { struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 buf[4]; @@ -1322,7 +1322,7 @@ static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ if (ttusb->revision == TTUSB_REV_2_2) buf[3] |= 0x20; - if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; -- GitLab From a9d6a80b41c04e8ff4c7442cc35f5df610863841 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey <adq_dvb@lidskialf.net> Date: Fri, 9 Sep 2005 13:02:31 -0700 Subject: [PATCH 124/563] [PATCH] dvb: frontend: s5h1420: fixes Misc. fixes. Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/frontends/s5h1420.c | 162 +++++++++++++++----------- drivers/media/dvb/frontends/s5h1420.h | 3 + drivers/media/dvb/ttpci/budget.c | 1 + 3 files changed, 97 insertions(+), 69 deletions(-) diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 4f396ac8de777..c7fe27fd530c8 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -48,7 +48,8 @@ struct s5h1420_state { }; static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); -static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings); +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings); static int debug = 0; @@ -91,7 +92,8 @@ static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag switch(voltage) { case SEC_VOLTAGE_13: - s5h1420_writereg(state, 0x3c, (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02); + s5h1420_writereg(state, 0x3c, + (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02); break; case SEC_VOLTAGE_18: @@ -112,18 +114,21 @@ static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) switch(tone) { case SEC_TONE_ON: - s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08); + s5h1420_writereg(state, 0x3b, + (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08); break; case SEC_TONE_OFF: - s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01); + s5h1420_writereg(state, 0x3b, + (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01); break; } return 0; } -static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +static int s5h1420_send_master_cmd (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd* cmd) { struct s5h1420_state* state = fe->demodulator_priv; u8 val; @@ -131,6 +136,9 @@ static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_m unsigned long timeout; int result = 0; + if (cmd->msg_len > 8) + return -EINVAL; + /* setup for DISEQC */ val = s5h1420_readreg(state, 0x3b); s5h1420_writereg(state, 0x3b, 0x02); @@ -138,16 +146,17 @@ static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_m /* write the DISEQC command bytes */ for(i=0; i< cmd->msg_len; i++) { - s5h1420_writereg(state, 0x3c + i, cmd->msg[i]); + s5h1420_writereg(state, 0x3d + i, cmd->msg[i]); } /* kick off transmission */ - s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | ((cmd->msg_len-1) << 4) | 0x08); + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | + ((cmd->msg_len-1) << 4) | 0x08); /* wait for transmission to complete */ timeout = jiffies + ((100*HZ) / 1000); while(time_before(jiffies, timeout)) { - if (s5h1420_readreg(state, 0x3b) & 0x08) + if (!(s5h1420_readreg(state, 0x3b) & 0x08)) break; msleep(5); @@ -161,7 +170,8 @@ static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_m return result; } -static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply) +static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, + struct dvb_diseqc_slave_reply* reply) { struct s5h1420_state* state = fe->demodulator_priv; u8 val; @@ -205,7 +215,7 @@ static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_ /* extract data */ for(i=0; i< length; i++) { - reply->msg[i] = s5h1420_readreg(state, 0x3c + i); + reply->msg[i] = s5h1420_readreg(state, 0x3d + i); } exit: @@ -236,7 +246,7 @@ static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicm s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08); /* wait for transmission to complete */ - timeout = jiffies + ((20*HZ) / 1000); + timeout = jiffies + ((100*HZ) / 1000); while(time_before(jiffies, timeout)) { if (!(s5h1420_readreg(state, 0x3b) & 0x08)) break; @@ -259,9 +269,9 @@ static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state) val = s5h1420_readreg(state, 0x14); if (val & 0x02) - status |= FE_HAS_SIGNAL; // FIXME: not sure if this is right + status |= FE_HAS_SIGNAL; if (val & 0x01) - status |= FE_HAS_CARRIER; // FIXME: not sure if this is right + status |= FE_HAS_CARRIER; val = s5h1420_readreg(state, 0x36); if (val & 0x01) status |= FE_HAS_VITERBI; @@ -284,8 +294,8 @@ static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status) /* determine lock state */ *status = s5h1420_get_status_bits(state); - /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert the inversion, - wait a bit and check again */ + /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert + the inversion, wait a bit and check again */ if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) { val = s5h1420_readreg(state, 0x32); if ((val & 0x07) == 0x03) { @@ -330,6 +340,10 @@ static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status) tmp = (tmp * 2 * 7) / 8; break; } + if (tmp == 0) { + printk("s5h1420: avoided division by 0\n"); + tmp = 1; + } tmp = state->fclk / tmp; /* set the MPEG_CLK_INTL for the calculated data rate */ @@ -368,16 +382,21 @@ static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber) s5h1420_writereg(state, 0x46, 0x1d); mdelay(25); - return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); + + *ber = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); + + return 0; } static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength) { struct s5h1420_state* state = fe->demodulator_priv; - u8 val = 0xff - s5h1420_readreg(state, 0x15); + u8 val = s5h1420_readreg(state, 0x15); - return (int) ((val << 8) | val); + *strength = (u16) ((val << 8) | val); + + return 0; } static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) @@ -386,7 +405,10 @@ static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) s5h1420_writereg(state, 0x46, 0x1f); mdelay(25); - return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); + + *ucblocks = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); + + return 0; } static void s5h1420_reset(struct s5h1420_state* state) @@ -396,11 +418,12 @@ static void s5h1420_reset(struct s5h1420_state* state) udelay(10); } -static void s5h1420_setsymbolrate(struct s5h1420_state* state, struct dvb_frontend_parameters *p) +static void s5h1420_setsymbolrate(struct s5h1420_state* state, + struct dvb_frontend_parameters *p) { u64 val; - val = (p->u.qpsk.symbol_rate / 1000) * (1<<24); + val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24); if (p->u.qpsk.symbol_rate <= 21000000) { val *= 2; } @@ -415,7 +438,7 @@ static void s5h1420_setsymbolrate(struct s5h1420_state* state, struct dvb_fronte static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) { - u64 val; + u64 val = 0; int sampling = 2; if (s5h1420_readreg(state, 0x05) & 0x2) @@ -427,10 +450,10 @@ static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) val |= s5h1420_readreg(state, 0x13); s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); - val *= (state->fclk / 1000); + val *= (state->fclk / 1000ULL); do_div(val, ((1<<24) * sampling)); - return (u32) (val * 1000); + return (u32) (val * 1000ULL); } static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset) @@ -463,46 +486,55 @@ static int s5h1420_getfreqoffset(struct s5h1420_state* state) /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so * divide fclk by 1000000 to get the correct value. */ - val = - ((val * (state->fclk/1000000)) / (1<<24)); + val = (((-val) * (state->fclk/1000000)) / (1<<24)); return val; } -static void s5h1420_setfec(struct s5h1420_state* state, struct dvb_frontend_parameters *p) +static void s5h1420_setfec_inversion(struct s5h1420_state* state, + struct dvb_frontend_parameters *p) { + u8 inversion = 0; + + if (p->inversion == INVERSION_OFF) { + inversion = state->config->invert ? 0x08 : 0; + } else if (p->inversion == INVERSION_ON) { + inversion = state->config->invert ? 0 : 0x08; + } + if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { - s5h1420_writereg(state, 0x31, 0x00); s5h1420_writereg(state, 0x30, 0x3f); + s5h1420_writereg(state, 0x31, 0x00 | inversion); } else { switch(p->u.qpsk.fec_inner) { case FEC_1_2: - s5h1420_writereg(state, 0x31, 0x10); s5h1420_writereg(state, 0x30, 0x01); + s5h1420_writereg(state, 0x31, 0x10 | inversion); break; case FEC_2_3: - s5h1420_writereg(state, 0x31, 0x11); s5h1420_writereg(state, 0x30, 0x02); + s5h1420_writereg(state, 0x31, 0x11 | inversion); break; case FEC_3_4: - s5h1420_writereg(state, 0x31, 0x12); s5h1420_writereg(state, 0x30, 0x04); - break; + s5h1420_writereg(state, 0x31, 0x12 | inversion); + break; case FEC_5_6: - s5h1420_writereg(state, 0x31, 0x13); s5h1420_writereg(state, 0x30, 0x08); + s5h1420_writereg(state, 0x31, 0x13 | inversion); break; case FEC_6_7: - s5h1420_writereg(state, 0x31, 0x14); s5h1420_writereg(state, 0x30, 0x10); + s5h1420_writereg(state, 0x31, 0x14 | inversion); break; case FEC_7_8: - s5h1420_writereg(state, 0x31, 0x15); s5h1420_writereg(state, 0x30, 0x20); + s5h1420_writereg(state, 0x31, 0x15 | inversion); break; default: @@ -536,22 +568,6 @@ static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) return FEC_NONE; } -static void s5h1420_setinversion(struct s5h1420_state* state, struct dvb_frontend_parameters *p) -{ - if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { - s5h1420_writereg(state, 0x31, 0x00); - s5h1420_writereg(state, 0x30, 0x3f); - } else { - u8 tmp = s5h1420_readreg(state, 0x31) & 0xf7; - tmp |= 0x10; - - if (p->inversion == INVERSION_ON) - tmp |= 0x80; - - s5h1420_writereg(state, 0x31, tmp); - } -} - static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) { if (s5h1420_readreg(state, 0x32) & 0x08) @@ -560,35 +576,35 @@ static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) return INVERSION_OFF; } -static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int s5h1420_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct s5h1420_state* state = fe->demodulator_priv; - u32 frequency_delta; + int frequency_delta; struct dvb_frontend_tune_settings fesettings; + u32 tmp; /* check if we should do a fast-tune */ memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); s5h1420_get_tune_settings(fe, &fesettings); frequency_delta = p->frequency - state->tunedfreq; - if ((frequency_delta > -fesettings.max_drift) && (frequency_delta < fesettings.max_drift) && + if ((frequency_delta > -fesettings.max_drift) && + (frequency_delta < fesettings.max_drift) && (frequency_delta != 0) && (state->fec_inner == p->u.qpsk.fec_inner) && (state->symbol_rate == p->u.qpsk.symbol_rate)) { - s5h1420_setfreqoffset(state, frequency_delta); + if (state->config->pll_set) { + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); + state->config->pll_set(fe, p, &tmp); + s5h1420_setfreqoffset(state, p->frequency - tmp); + } return 0; } /* first of all, software reset */ s5h1420_reset(state); - /* set tuner PLL */ - if (state->config->pll_set) { - s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); - state->config->pll_set(fe, p, &state->tunedfreq); - s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe); - } - /* set s5h1420 fclk PLL according to desired symbol rate */ if (p->u.qpsk.symbol_rate > 28000000) { state->fclk = 88000000; @@ -609,8 +625,9 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* set misc registers */ s5h1420_writereg(state, 0x02, 0x00); + s5h1420_writereg(state, 0x06, 0x00); s5h1420_writereg(state, 0x07, 0xb0); - s5h1420_writereg(state, 0x0a, 0x67); + s5h1420_writereg(state, 0x0a, 0xe7); s5h1420_writereg(state, 0x0b, 0x78); s5h1420_writereg(state, 0x0c, 0x48); s5h1420_writereg(state, 0x0d, 0x6b); @@ -626,21 +643,26 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* start QPSK */ s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1); - /* set the frequency offset to adjust for PLL inaccuracy */ - s5h1420_setfreqoffset(state, p->frequency - state->tunedfreq); + /* set tuner PLL */ + if (state->config->pll_set) { + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); + state->config->pll_set(fe, p, &tmp); + s5h1420_setfreqoffset(state, 0); + } /* set the reset of the parameters */ s5h1420_setsymbolrate(state, p); - s5h1420_setinversion(state, p); - s5h1420_setfec(state, p); + s5h1420_setfec_inversion(state, p); state->fec_inner = p->u.qpsk.fec_inner; state->symbol_rate = p->u.qpsk.symbol_rate; state->postlocked = 0; + state->tunedfreq = p->frequency; return 0; } -static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int s5h1420_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct s5h1420_state* state = fe->demodulator_priv; @@ -652,7 +674,8 @@ static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return 0; } -static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) { if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { fesettings->min_delay_ms = 50; @@ -717,7 +740,8 @@ static void s5h1420_release(struct dvb_frontend* fe) static struct dvb_frontend_ops s5h1420_ops; -struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, struct i2c_adapter* i2c) +struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, + struct i2c_adapter* i2c) { struct s5h1420_state* state = NULL; u8 identity; diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h index b687fc77ceb32..872028ddf2a2d 100644 --- a/drivers/media/dvb/frontends/s5h1420.h +++ b/drivers/media/dvb/frontends/s5h1420.h @@ -30,6 +30,9 @@ struct s5h1420_config /* the demodulator's i2c address */ u8 demod_address; + /* does the inversion require inversion? */ + u8 invert:1; + /* PLL maintenance */ int (*pll_init)(struct dvb_frontend* fe); int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout); diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 5552ef5019966..43d6c8268642b 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -480,6 +480,7 @@ static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete static struct s5h1420_config s5h1420_config = { .demod_address = 0x53, + .invert = 1, .pll_set = s5h1420_pll_set, }; -- GitLab From 78639a3f81d14117d1841476771d7a4736e7b9d1 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey <adq_dvb@lidskialf.net> Date: Fri, 9 Sep 2005 13:02:32 -0700 Subject: [PATCH 125/563] [PATCH] dvb: frontend: stv0299: support reading both BER and UCBLOCKS Allow the stv0299 to read the BER and UCBLOCKS. Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/frontends/stv0299.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index db66d417df382..2d62931f20b54 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -63,12 +63,8 @@ struct stv0299_state { u32 tuner_frequency; u32 symbol_rate; fe_code_rate_t fec_inner; - int errmode; }; -#define STATUS_BER 0 -#define STATUS_UCBLOCKS 1 - static int debug; static int debug_legacy_dish_switch; #define dprintk(args...) \ @@ -520,7 +516,8 @@ static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) { struct stv0299_state* state = fe->demodulator_priv; - if (state->errmode != STATUS_BER) return 0; + stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x10); + msleep(100); *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); return 0; @@ -559,8 +556,9 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { struct stv0299_state* state = fe->demodulator_priv; - if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0; - else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); + stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x30); + msleep(100); + *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); return 0; } @@ -709,7 +707,6 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, state->tuner_frequency = 0; state->symbol_rate = 0; state->fec_inner = 0; - state->errmode = STATUS_BER; /* check if the demod is there */ stv0299_writeregI(state, 0x02, 0x34); /* standby off */ -- GitLab From c2026b3af0c8ad33ef253a950c271f2d0da111b6 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey <adq_dvb@lidskialf.net> Date: Fri, 9 Sep 2005 13:02:33 -0700 Subject: [PATCH 126/563] [PATCH] dvb: frontend: tda1004x: fix SNR reading Fix SNR reading Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/frontends/tda1004x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index ab0c032472cc0..74cea9f8d7210 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -1046,8 +1046,7 @@ static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr) tmp = tda1004x_read_byte(state, TDA1004X_SNR); if (tmp < 0) return -EIO; - if (tmp) - tmp = 255 - tmp; + tmp = 255 - tmp; *snr = ((tmp << 8) | tmp); dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr); -- GitLab From 6816a4c183e62bca1fa4812214e483ab503dcb7d Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach <js@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:34 -0700 Subject: [PATCH 127/563] [PATCH] dvb: frontend: ves1820: improve tuning Reset acgconf register after tuning to improve locking, as suggested by Marco Schluessler. Minor cleanups in ves1820_init(). Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/frontends/ves1820.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 70fb44b391a75..c6d276618e86f 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -194,19 +194,18 @@ static int ves1820_init(struct dvb_frontend* fe) { struct ves1820_state* state = fe->demodulator_priv; int i; - int val; ves1820_writereg(state, 0, 0); - for (i = 0; i < 53; i++) { - val = ves1820_inittab[i]; - if ((i == 2) && (state->config->selagc)) val |= 0x08; - ves1820_writereg(state, i, val); - } + for (i = 0; i < sizeof(ves1820_inittab); i++) + ves1820_writereg(state, i, ves1820_inittab[i]); + if (state->config->selagc) + ves1820_writereg(state, 2, ves1820_inittab[2] | 0x08); ves1820_writereg(state, 0x34, state->pwm); - if (state->config->pll_init) state->config->pll_init(fe); + if (state->config->pll_init) + state->config->pll_init(fe); return 0; } @@ -234,7 +233,7 @@ static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_p ves1820_writereg(state, 0x09, reg0x09[real_qam]); ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion); - + ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0)); return 0; } -- GitLab From d897275500d8fac919a11073eb587ce0e3fcc36c Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach <js@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:34 -0700 Subject: [PATCH 128/563] [PATCH] dvb: frontend: cx24110: DiSEqC fix Fix DiSEqC switching (one bug fix suggested by Peter Hettkamp, and one experimentally determined msleep(30) suggested by Adam Szalkowski). Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/frontends/cx24110.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 555d472e42ded..71b54094bda8a 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -398,7 +398,7 @@ static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t return -EINVAL; rv = cx24110_readreg(state, 0x77); - cx24110_writereg(state, 0x77, rv|0x04); + cx24110_writereg(state, 0x77, rv | 0x04); rv = cx24110_readreg(state, 0x76); cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit)); @@ -418,7 +418,8 @@ static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, cx24110_writereg(state, 0x79 + i, cmd->msg[i]); rv = cx24110_readreg(state, 0x77); - cx24110_writereg(state, 0x77, rv|0x04); + cx24110_writereg(state, 0x77, rv & ~0x04); + msleep(30); /* reportedly fixes switching problems */ rv = cx24110_readreg(state, 0x76); -- GitLab From 296c786a0d2122b1e47c80ca717d8a8ac36402c1 Mon Sep 17 00:00:00 2001 From: Adam Szalkowski <adamsz@gmx.net> Date: Fri, 9 Sep 2005 13:02:35 -0700 Subject: [PATCH 129/563] [PATCH] dvb: frontend: cx24110: another DiSEqC fix Fix DiSEqC problems. Signed-off-by: Adam Szalkowski <adam@szalkowski.de> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/frontends/cx24110.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 71b54094bda8a..eb4833ee72bee 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -398,7 +398,8 @@ static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t return -EINVAL; rv = cx24110_readreg(state, 0x77); - cx24110_writereg(state, 0x77, rv | 0x04); + if (!(rv & 0x04)) + cx24110_writereg(state, 0x77, rv | 0x04); rv = cx24110_readreg(state, 0x76); cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit)); @@ -418,14 +419,16 @@ static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, cx24110_writereg(state, 0x79 + i, cmd->msg[i]); rv = cx24110_readreg(state, 0x77); - cx24110_writereg(state, 0x77, rv & ~0x04); - msleep(30); /* reportedly fixes switching problems */ + if (rv & 0x04) { + cx24110_writereg(state, 0x77, rv & ~0x04); + msleep(30); /* reportedly fixes switching problems */ + } rv = cx24110_readreg(state, 0x76); cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); - for (i=500; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40);) - ; /* wait for LNB ready */ + for (i=100; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40);) + msleep(1); /* wait for LNB ready */ return 0; } -- GitLab From c589ebfce79834a9617c44d7ec0f608fa70eb42d Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach <js@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:37 -0700 Subject: [PATCH 130/563] [PATCH] dvb: frontend: cx24110: clean up timeout handling. Clean up timeout handling. Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/frontends/cx24110.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index eb4833ee72bee..d4b97989e3ed0 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -387,8 +387,9 @@ static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) { - int rv, bit, i; + int rv, bit; struct cx24110_state *state = fe->demodulator_priv; + unsigned long timeout; if (burst == SEC_MINI_A) bit = 0x00; @@ -403,8 +404,9 @@ static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t rv = cx24110_readreg(state, 0x76); cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit)); - for (i = 500; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40) ; ) - ; /* wait for LNB ready */ + timeout = jiffies + msecs_to_jiffies(100); + while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40)) + ; /* wait for LNB ready */ return 0; } @@ -414,6 +416,7 @@ static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, { int i, rv; struct cx24110_state *state = fe->demodulator_priv; + unsigned long timeout; for (i = 0; i < cmd->msg_len; i++) cx24110_writereg(state, 0x79 + i, cmd->msg[i]); @@ -427,8 +430,9 @@ static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, rv = cx24110_readreg(state, 0x76); cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); - for (i=100; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40);) - msleep(1); /* wait for LNB ready */ + timeout = jiffies + msecs_to_jiffies(100); + while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40)) + ; /* wait for LNB ready */ return 0; } -- GitLab From 593cbf3dcbffc852cf91a30951eb518b59bf7322 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher <pb@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:38 -0700 Subject: [PATCH 131/563] [PATCH] dvb: frontend: stv0297: QAM128 tuning improvement while investigating the QAM_128-issue with the stv0297-driver for the Cablestar (which is not the same as the one in dvb-kernel CVS, yet), I fixed it, not by increasing the timeout, but by disabling the corner-detection for QAM_128 and higher. This patch has been tested on dvb-kernel cvs, and has been reported to work by multiple users. Some cards still need timeout increase on top of this patch. This will be addressed later. Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/frontends/stv0297.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 928aca052afe3..01eb41990e8a8 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -606,7 +606,13 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par stv0297_set_inversion(state, inversion); /* kick off lock */ - stv0297_writereg_mask(state, 0x88, 0x08, 0x08); + /* Disable corner detection for higher QAMs */ + if (p->u.qam.modulation == QAM_128 || + p->u.qam.modulation == QAM_256) + stv0297_writereg_mask(state, 0x88, 0x08, 0x00); + else + stv0297_writereg_mask(state, 0x88, 0x08, 0x08); + stv0297_writereg_mask(state, 0x5a, 0x20, 0x00); stv0297_writereg_mask(state, 0x6a, 0x01, 0x01); stv0297_writereg_mask(state, 0x43, 0x40, 0x40); -- GitLab From 80e27e20619902b11aa255081fd83eab10fc0839 Mon Sep 17 00:00:00 2001 From: Mac Michaels <wmichaels1@earthlink.net> Date: Fri, 9 Sep 2005 13:02:40 -0700 Subject: [PATCH 132/563] [PATCH] dvb: frontend: or51132: remove bogus optimization attempt This fix has also been applied to lgdt330x. There is an optimization that keeps track of the frequency tuned by the digital decoder. The digital driver does not set the frequency if it has not changed since it was tuned. The analog tuner driver knows nothing about the frequency saved by the digital driver. When the frequency is set using the video4linux code with tvtime, the hardware get changed but the digital driver's state does not get updated. Switch back to the same digital channel and the driver finds no change in frequency so the tuner is not reset to the digital frequency. The work around is to remove the check and always set the tuner to the specified frequency. Signed-off-by: Mac Michaels <wmichaels1@earthlink.net> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/frontends/or51132.c | 29 ++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index cc0a77c790f1a..b6d0eecc59eb0 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -370,22 +370,19 @@ static int or51132_set_parameters(struct dvb_frontend* fe, or51132_setmode(fe); } - /* Change only if we are actually changing the channel */ - if (state->current_frequency != param->frequency) { - dvb_pll_configure(state->config->pll_desc, buf, - param->frequency, 0); - dprintk("set_parameters tuner bytes: 0x%02x 0x%02x " - "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]); - if (i2c_writebytes(state, state->config->pll_address ,buf, 4)) - printk(KERN_WARNING "or51132: set_parameters error " - "writing to tuner\n"); - - /* Set to current mode */ - or51132_setmode(fe); - - /* Update current frequency */ - state->current_frequency = param->frequency; - } + dvb_pll_configure(state->config->pll_desc, buf, + param->frequency, 0); + dprintk("set_parameters tuner bytes: 0x%02x 0x%02x " + "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]); + if (i2c_writebytes(state, state->config->pll_address ,buf, 4)) + printk(KERN_WARNING "or51132: set_parameters error " + "writing to tuner\n"); + + /* Set to current mode */ + or51132_setmode(fe); + + /* Update current frequency */ + state->current_frequency = param->frequency; return 0; } -- GitLab From 3706a4da2012679631da6d22e86c6a34cde7419a Mon Sep 17 00:00:00 2001 From: Patrick Boettcher <pb@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:41 -0700 Subject: [PATCH 133/563] [PATCH] dvb: usb: add TwinhanDTV StarBox support Add driver for the TwinhanDTV StarBox and clones. Thanks to Ralph Metzler for his initial work on this box and thanks to Twinhan for their support. Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-usb/Kconfig | 23 +- drivers/media/dvb/dvb-usb/Makefile | 3 + drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 6 +- drivers/media/dvb/dvb-usb/vp702x-fe.c | 339 ++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/vp702x.c | 290 ++++++++++++++++++++ drivers/media/dvb/dvb-usb/vp702x.h | 109 ++++++++ 6 files changed, 765 insertions(+), 5 deletions(-) create mode 100644 drivers/media/dvb/dvb-usb/vp702x-fe.c create mode 100644 drivers/media/dvb/dvb-usb/vp702x.c create mode 100644 drivers/media/dvb/dvb-usb/vp702x.h diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 612e5b087b1c1..54e2b29076b12 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -93,13 +93,30 @@ config DVB_USB_DIGITV Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. config DVB_USB_VP7045 - tristate "TwinhanDTV Alpha/MagicBoxII and DNTV tinyUSB2 DVB-T USB2.0 support" + tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support" depends on DVB_USB help Say Y here to support the + TwinhanDTV Alpha (stick) (VP-7045), - TwinhanDTV MagicBox II (VP-7046) and - DigitalNow TinyUSB 2 DVB-t DVB-T USB2.0 receivers. + TwinhanDTV MagicBox II (VP-7046), + DigitalNow TinyUSB 2 DVB-t, + DigitalRise USB 2.0 Ter (Beetle) and + TYPHOON DVB-T USB DRIVE + + DVB-T USB2.0 receivers. + +config DVB_USB_VP702X + tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support" + depends on DVB_USB + help + Say Y here to support the + + TwinhanDTV StarBox, + DigitalRise USB Starbox and + TYPHOON DVB-S USB 2.0 BOX + + DVB-S USB2.0 receivers. config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 746d87ed6f328..2dc9aad9681e3 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -4,6 +4,9 @@ obj-$(CONFIG_DVB_USB) += dvb-usb.o dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o +dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o +obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o + dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 794d513a8480f..2b249c75fb026 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -52,12 +52,14 @@ #define USB_PID_KWORLD_VSTREAM_WARM 0x17df #define USB_PID_TWINHAN_VP7041_COLD 0x3201 #define USB_PID_TWINHAN_VP7041_WARM 0x3202 +#define USB_PID_TWINHAN_VP7020_COLD 0x3203 +#define USB_PID_TWINHAN_VP7020_WARM 0x3204 #define USB_PID_TWINHAN_VP7045_COLD 0x3205 #define USB_PID_TWINHAN_VP7045_WARM 0x3206 -#define USB_PID_DNTV_TINYUSB2_COLD 0x3223 -#define USB_PID_DNTV_TINYUSB2_WARM 0x3224 #define USB_PID_TWINHAN_VP7021_COLD 0x3207 #define USB_PID_TWINHAN_VP7021_WARM 0x3208 +#define USB_PID_DNTV_TINYUSB2_COLD 0x3223 +#define USB_PID_DNTV_TINYUSB2_WARM 0x3224 #define USB_PID_ULTIMA_TVBOX_COLD 0x8105 #define USB_PID_ULTIMA_TVBOX_WARM 0x8106 #define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107 diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c new file mode 100644 index 0000000000000..f20d8dbd0be82 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c @@ -0,0 +1,339 @@ +/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0 + * DVB-S receiver. + * + * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de> + * Metzler Brothers Systementwicklung GbR + * + * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de> + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * This file can be removed soon, after the DST-driver is rewritten to provice + * the frontend-controlling separately. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + * + */ +#include "vp702x.h" + +struct vp702x_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; + + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone_mode; + + u8 lnb_buf[8]; + + u8 lock; + u8 sig; + u8 snr; + + unsigned long next_status_check; + unsigned long status_check_interval; +}; + +static int vp702x_fe_refresh_state(struct vp702x_fe_state *st) +{ + u8 buf[10]; + if (time_after(jiffies,st->next_status_check)) { + vp702x_usb_in_op(st->d,READ_STATUS,0,0,buf,10); + + st->lock = buf[4]; + vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x11,0,&st->snr,1); + vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x15,0,&st->sig,1); + + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + +static u8 vp702x_chksum(u8 *buf,int f, int count) +{ + u8 s = 0; + int i; + for (i = f; i < f+count; i++) + s += buf[i]; + return ~s+1; +} + +static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + deb_fe("%s\n",__FUNCTION__); + + if (st->lock == 0) + *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; + else + *status = 0; + + deb_fe("real state: %x\n",*status); + *status = 0x1f; + + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1000; + else + st->status_check_interval = 250; + return 0; +} + +/* not supported by this Frontend */ +static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + *ber = 0; + return 0; +} + +/* not supported by this Frontend */ +static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + *unc = 0; + return 0; +} + +static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + + *strength = (st->sig << 8) | st->sig; + return 0; +} + +static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + u8 _snr; + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + + _snr = (st->snr & 0x1f) * 0xff / 0x1f; + *snr = (_snr << 8) | _snr; + return 0; +} + +static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + deb_fe("%s\n",__FUNCTION__); + tune->min_delay_ms = 2000; + return 0; +} + +static int vp702x_fe_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + u32 freq = fep->frequency/1000; + /*CalFrequency*/ +/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */ + u64 sr; + u8 cmd[8] = { 0 },ibuf[10]; + + cmd[0] = (freq >> 8) & 0x7f; + cmd[1] = freq & 0xff; + cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */ + + sr = (u64) (fep->u.qpsk.symbol_rate/1000) << 20; + do_div(sr,88000); + cmd[3] = (sr >> 12) & 0xff; + cmd[4] = (sr >> 4) & 0xff; + cmd[5] = (sr << 4) & 0xf0; + + deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %Lu (%Lx)\n", + fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, sr, sr); + +/* if (fep->inversion == INVERSION_ON) + cmd[6] |= 0x80; */ + + if (st->voltage == SEC_VOLTAGE_18) + cmd[6] |= 0x40; + +/* if (fep->u.qpsk.symbol_rate > 8000000) + cmd[6] |= 0x20; + + if (fep->frequency < 1531000) + cmd[6] |= 0x04; + + if (st->tone_mode == SEC_TONE_ON) + cmd[6] |= 0x01;*/ + + cmd[7] = vp702x_chksum(cmd,0,7); + + st->status_check_interval = 250; + st->next_status_check = jiffies; + + vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0); + msleep(30); + vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); + + if (ibuf[2] == 0 && ibuf[3] == 0) + deb_fe("tuning failed.\n"); + else + deb_fe("tuning succeeded.\n"); + + return 0; +} + +static int vp702x_fe_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + deb_fe("%s\n",__FUNCTION__); + return 0; +} + +static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *m) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + u8 cmd[8],ibuf[10]; + memset(cmd,0,8); + + deb_fe("%s\n",__FUNCTION__); + + if (m->msg_len > 4) + return -EINVAL; + + cmd[1] = SET_DISEQC_CMD; + cmd[2] = m->msg_len; + memcpy(&cmd[3], m->msg, m->msg_len); + cmd[7] = vp702x_chksum(cmd,0,7); + + vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); + + if (ibuf[2] == 0 && ibuf[3] == 0) + deb_fe("diseqc cmd failed.\n"); + else + deb_fe("diseqc cmd succeeded.\n"); + + return 0; +} + +static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +{ + deb_fe("%s\n",__FUNCTION__); + return 0; +} + +static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + u8 ibuf[10]; + deb_fe("%s\n",__FUNCTION__); + + st->tone_mode = tone; + + if (tone == SEC_TONE_ON) + st->lnb_buf[2] = 0x02; + else + st->lnb_buf[2] = 0x00; + + st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7); + + vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100); + if (ibuf[2] == 0 && ibuf[3] == 0) + deb_fe("set_tone cmd failed.\n"); + else + deb_fe("set_tone cmd succeeded.\n"); + + return 0; +} + +static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t + voltage) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + u8 ibuf[10]; + deb_fe("%s\n",__FUNCTION__); + + st->voltage = voltage; + + if (voltage != SEC_VOLTAGE_OFF) + st->lnb_buf[4] = 0x01; + else + st->lnb_buf[4] = 0x00; + + st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7); + + vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100); + if (ibuf[2] == 0 && ibuf[3] == 0) + deb_fe("set_voltage cmd failed.\n"); + else + deb_fe("set_voltage cmd succeeded.\n"); + + return 0; +} + +static void vp702x_fe_release(struct dvb_frontend* fe) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + kfree(st); +} + +static struct dvb_frontend_ops vp702x_fe_ops; + +struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d) +{ + struct vp702x_fe_state *s = kmalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL); + if (s == NULL) + goto error; + memset(s,0,sizeof(struct vp702x_fe_state)); + + s->d = d; + s->fe.ops = &vp702x_fe_ops; + s->fe.demodulator_priv = s; + + s->lnb_buf[1] = SET_LNB_POWER; + s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */ + + goto success; +error: + return NULL; +success: + return &s->fe; +} + + +static struct dvb_frontend_ops vp702x_fe_ops = { + .info = { + .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, /* kHz for QPSK frontends */ + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + .release = vp702x_fe_release, + + .init = NULL, + .sleep = NULL, + + .set_frontend = vp702x_fe_set_frontend, + .get_frontend = vp702x_fe_get_frontend, + .get_tune_settings = vp702x_fe_get_tune_settings, + + .read_status = vp702x_fe_read_status, + .read_ber = vp702x_fe_read_ber, + .read_signal_strength = vp702x_fe_read_signal_strength, + .read_snr = vp702x_fe_read_snr, + .read_ucblocks = vp702x_fe_read_unc_blocks, + + .diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg, + .diseqc_send_burst = vp702x_fe_send_diseqc_burst, + .set_tone = vp702x_fe_set_tone, + .set_voltage = vp702x_fe_set_voltage, +}; diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c new file mode 100644 index 0000000000000..1f5034ca1152c --- /dev/null +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -0,0 +1,290 @@ +/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S + * receiver. + * + * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de> + * Metzler Brothers Systementwicklung GbR + * + * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de> + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "vp702x.h" + +/* debug */ +int dvb_usb_vp702x_debug; +module_param_named(debug,dvb_usb_vp702x_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +struct vp702x_state { + u8 pid_table[17]; /* [16] controls the pid_table state */ +}; + +/* check for mutex FIXME */ +int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +{ + int ret = 0,try = 0; + + while (ret >= 0 && ret != blen && try < 3) { + ret = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_IN, + value,index,b,blen, + 2000); + deb_info("reading number %d (ret: %d)\n",try,ret); + try++; + } + + if (ret < 0 || ret != blen) { + warn("usb in operation failed."); + ret = -EIO; + } else + ret = 0; + + deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + return ret; +} + +int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +{ + deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + if (usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_OUT, + value,index,b,blen, + 2000) != blen) { + warn("usb out operation failed."); + return -EIO; + } else + return 0; +} + +int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec) +{ + int ret; + + if ((ret = down_interruptible(&d->usb_sem))) + return ret; + + if ((ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen)) < 0) + goto unlock; + msleep(msec); + ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen); + +unlock: + up(&d->usb_sem); + + return ret; +} + +int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o, int olen, u8 *i, int ilen, int msec) +{ + u8 bout[olen+2]; + u8 bin[ilen+1]; + int ret = 0; + + bout[0] = 0x00; + bout[1] = cmd; + memcpy(&bout[2],o,olen); + + ret = vp702x_usb_inout_op(d, bout, olen+2, bin, ilen+1,msec); + + if (ret == 0) + memcpy(i,&bin[1],ilen); + + return ret; +} + +static int vp702x_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff) +{ + struct vp702x_state *st = d->priv; + u8 buf[9]; + + if (onoff) { + st->pid_table[16] |= 1 << index; + st->pid_table[index*2] = (pid >> 8) & 0xff; + st->pid_table[index*2+1] = pid & 0xff; + } else { + st->pid_table[16] &= ~(1 << index); + st->pid_table[index*2] = st->pid_table[index*2+1] = 0; + } + + return vp702x_usb_inout_cmd(d,SET_PID_FILTER,st->pid_table,17,buf,9,10); +} + +static int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + vp702x_usb_in_op(d,RESET_TUNER,0,0,NULL,0); + + vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0); + return vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0); +} + +/* keys for the enclosed remote control */ +static struct dvb_usb_rc_key vp702x_rc_keys[] = { + { 0x00, 0x01, KEY_1 }, + { 0x00, 0x02, KEY_2 }, +}; + +/* remote control stuff (does not work with my box) */ +static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[10]; + int i; + +/* remove the following return to enabled remote querying */ + return 0; + + vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10); + + deb_rc("remote query key: %x %d\n",key[1],key[1]); + + if (key[1] == 0x44) { + *state = REMOTE_NO_KEY_PRESSED; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(vp702x_rc_keys); i++) + if (vp702x_rc_keys[i].custom == key[1]) { + *state = REMOTE_KEY_PRESSED; + *event = vp702x_rc_keys[i].event; + break; + } + return 0; +} + +static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) +{ + u8 macb[9]; + if (vp702x_usb_inout_cmd(d, GET_MAC_ADDRESS, NULL, 0, macb, 9, 10)) + return -EIO; + memcpy(mac,&macb[3],6); + return 0; +} + +static int vp702x_frontend_attach(struct dvb_usb_device *d) +{ + u8 buf[9] = { 0 }; + + if (vp702x_usb_inout_cmd(d, GET_SYSTEM_STRING, NULL, 0, buf, 9, 10)) + return -EIO; + + buf[8] = '\0'; + info("system string: %s",&buf[1]); + + d->fe = vp702x_fe_attach(d); + return 0; +} + +static struct dvb_usb_properties vp702x_properties; + +static int vp702x_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + + usb_clear_halt(udev,usb_sndctrlpipe(udev,0)); + usb_clear_halt(udev,usb_rcvctrlpipe(udev,0)); + + return dvb_usb_device_init(intf,&vp702x_properties,THIS_MODULE); +} + +static struct usb_device_id vp702x_usb_table [] = { + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_WARM) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, vp702x_usb_table); + +static struct dvb_usb_properties vp702x_properties = { + .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, + .pid_filter_count = 8, /* !!! */ + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-vp702x-01.fw", + + .pid_filter = vp702x_pid_filter, + .power_ctrl = vp702x_power_ctrl, + .frontend_attach = vp702x_frontend_attach, + .read_mac_address = vp702x_read_mac_addr, + + .rc_key_map = vp702x_rc_keys, + .rc_key_map_size = ARRAY_SIZE(vp702x_rc_keys), + .rc_interval = 400, + .rc_query = vp702x_rc_query, + + .size_of_priv = sizeof(struct vp702x_state), + + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + + .num_device_descs = 2, + .devices = { + { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)", + .cold_ids = { &vp702x_usb_table[0], NULL }, + .warm_ids = { &vp702x_usb_table[1], NULL }, + }, + { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)", + .cold_ids = { &vp702x_usb_table[2], NULL }, + .warm_ids = { &vp702x_usb_table[3], NULL }, + }, + { 0 }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver vp702x_usb_driver = { + .owner = THIS_MODULE, + .name = "dvb-usb-vp702x", + .probe = vp702x_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = vp702x_usb_table, +}; + +/* module stuff */ +static int __init vp702x_usb_module_init(void) +{ + int result; + if ((result = usb_register(&vp702x_usb_driver))) { + err("usb_register failed. (%d)",result); + return result; + } + + return 0; +} + +static void __exit vp702x_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&vp702x_usb_driver); +} + +module_init(vp702x_usb_module_init); +module_exit(vp702x_usb_module_exit); + +MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); +MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones"); +MODULE_VERSION("1.0-alpha"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h new file mode 100644 index 0000000000000..4a3e8c7eca2b8 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/vp702x.h @@ -0,0 +1,109 @@ +#ifndef _DVB_USB_VP7021_H_ +#define _DVB_USB_VP7021_H_ + +#define DVB_USB_LOG_PREFIX "vp702x" +#include "dvb-usb.h" + +extern int dvb_usb_vp702x_debug; +#define deb_info(args...) dprintk(dvb_usb_vp702x_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_vp702x_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_vp702x_debug,0x04,args) +#define deb_fe(args...) dprintk(dvb_usb_vp702x_debug,0x08,args) + +/* commands are read and written with USB control messages */ + +/* consecutive read/write operation */ +#define REQUEST_OUT 0xB2 +#define REQUEST_IN 0xB3 + +/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0 + * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer + * the returning buffer looks as follows + * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */ + +#define GET_TUNER_STATUS 0x05 +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */ + +#define GET_SYSTEM_STRING 0x06 +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */ + +#define SET_DISEQC_CMD 0x08 +/* additional out buffer: + * 0 1 2 3 4 + * len X1 X2 X3 X4 + * additional in buffer: + * 0 1 2 + * N/A 0 0 b[1] == b[2] == 0 -> success otherwise not */ + +#define SET_LNB_POWER 0x09 +/* additional out buffer: + * 0 1 2 + * 0x00 0xff 1 = on, 0 = off + * additional in buffer: + * 0 1 2 + * N/A 0 0 b[1] == b[2] == 0 -> success otherwise not */ + +#define GET_MAC_ADDRESS 0x0A +/* #define GET_MAC_ADDRESS 0x0B */ +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */ + +#define SET_PID_FILTER 0x11 +/* additional in buffer: + * 0 1 ... 14 15 16 + * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */ + +/* request: 0xB2; i: 0; v: 0; + * b[0] != 0 -> tune and lock a channel + * 0 1 2 3 4 5 6 7 + * freq0 freq1 divstep srate0 srate1 srate2 flag chksum + */ + + +/* one direction requests */ +#define READ_REMOTE_REQ 0xB4 +/* IN i: 0; v: 0; b[0] == request, b[1] == key */ + +#define READ_PID_NUMBER_REQ 0xB5 +/* IN i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */ + +#define WRITE_EEPROM_REQ 0xB6 +/* OUT i: offset; v: value to write; no extra buffer */ + +#define READ_EEPROM_REQ 0xB7 +/* IN i: bufferlen; v: offset; buffer with bufferlen bytes */ + +#define READ_STATUS 0xB8 +/* IN i: 0; v: 0; bufferlen 10 */ + +#define READ_TUNER_REG_REQ 0xB9 +/* IN i: 0; v: register; b[0] = value */ + +#define READ_FX2_REG_REQ 0xBA +/* IN i: offset; v: 0; b[0] = value */ + +#define WRITE_FX2_REG_REQ 0xBB +/* OUT i: offset; v: value to write; 1 byte extra buffer */ + +#define SET_TUNER_POWER_REQ 0xBC +/* IN i: 0 = power off, 1 = power on */ + +#define WRITE_TUNER_REG_REQ 0xBD +/* IN i: register, v: value to write, no extra buffer */ + +#define RESET_TUNER 0xBE +/* IN i: 0, v: 0, no extra buffer */ + +extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); + +extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); +extern int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o, int olen, u8 *i, int ilen, int msec); +extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); + +#endif -- GitLab From e69339d9a43d4691f6a05c5a54a00d54814aaa68 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher <pb@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:42 -0700 Subject: [PATCH 134/563] [PATCH] dvb: usb: dibusb: Kworld Xpert DVB-T USB2.0 support Add USB IDs of the Kworld Xpert DVB-T USB2.0 (clone of the ADStech box). Thanks to Marcus Hagn for testing. Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-usb/dibusb-mb.c | 14 ++++++++++---- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 828b5182e16c3..c9f3e90ee25fd 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -126,10 +126,12 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { /* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, /* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, +/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) }, + // #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs -/* 27 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +/* 28 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, #endif { } /* Terminating entry */ }; @@ -262,7 +264,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { }, #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", - { &dibusb_dib3000mb_table[27], NULL }, + { &dibusb_dib3000mb_table[28], NULL }, { NULL }, }, #endif @@ -306,12 +308,16 @@ static struct dvb_usb_properties dibusb2_0b_properties = { } }, - .num_device_descs = 1, + .num_device_descs = 2, .devices = { - { "KWorld/ADSTech Instant DVB-T USB 2.0", + { "KWorld/ADSTech Instant DVB-T USB2.0", { &dibusb_dib3000mb_table[23], NULL }, { &dibusb_dib3000mb_table[24], NULL }, }, + { "KWorld Xpert DVB-T USB2.0", + { &dibusb_dib3000mb_table[27], NULL }, + { NULL } + }, } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2b249c75fb026..1b978389e4ecb 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -24,6 +24,7 @@ #define USB_VID_HANFTEK 0x15f4 #define USB_VID_HAUPPAUGE 0x2040 #define USB_VID_HYPER_PALTEK 0x1025 +#define USB_VID_KWORLD 0xeb2a #define USB_VID_KYE 0x0458 #define USB_VID_MEDION 0x1660 #define USB_VID_VISIONPLUS 0x13d3 -- GitLab From 54127d64d2094207e0e12a4a9eec33573f25f7ac Mon Sep 17 00:00:00 2001 From: Andreas Oberritter <obi@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:43 -0700 Subject: [PATCH 135/563] [PATCH] dvb: usb: removed empty module_init/exit calls Removed empty module_init/exit calls. Signed-off-by: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-usb/dvb-usb-init.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index 65f0c095abc91..ea1098a6c7a86 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -196,19 +196,6 @@ void dvb_usb_device_exit(struct usb_interface *intf) } EXPORT_SYMBOL(dvb_usb_device_exit); -/* module stuff */ -static int __init dvb_usb_module_init(void) -{ - return 0; -} - -static void __exit dvb_usb_module_exit(void) -{ -} - -module_init (dvb_usb_module_init); -module_exit (dvb_usb_module_exit); - MODULE_VERSION("0.3"); MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); -- GitLab From 43bc3f41e4b1bb88adaef593f50c1f032bf0e876 Mon Sep 17 00:00:00 2001 From: "Ye Jianjun (Joey" <joeyye@trident.com.cn> Date: Fri, 9 Sep 2005 13:02:44 -0700 Subject: [PATCH 136/563] [PATCH] dvb: usb: dtt200u: copy frontend_ops before modifying Fix: copy frontend_ops before modifying Signed-off-by: Ye Jianjun (Joey) <joeyye@trident.com.cn> Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-usb/dtt200u-fe.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c index b032523b07bc4..0a94ec22aeb86 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -18,6 +18,7 @@ struct dtt200u_fe_state { struct dvb_frontend_parameters fep; struct dvb_frontend frontend; + struct dvb_frontend_ops ops; }; static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat) @@ -163,8 +164,9 @@ struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d) deb_info("attaching frontend dtt200u\n"); state->d = d; + memcpy(&state->ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops)); - state->frontend.ops = &dtt200u_fe_ops; + state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; goto success; -- GitLab From 62703b9d72114a563488cd4be6d0827618395589 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher <pb@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:46 -0700 Subject: [PATCH 137/563] [PATCH] dvb: usb: dtt200u: add proper device names Added names for clones of the DVB-T stick. Whitespace cleanups. Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-usb/dtt200u.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 47dba6e45968b..9d74f48284faf 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -106,12 +106,11 @@ static int dtt200u_usb_probe(struct usb_interface *intf, } static struct usb_device_id dtt200u_usb_table [] = { -// { USB_DEVICE(0x04b4,0x8613) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, - { 0 }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, + { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); @@ -189,7 +188,7 @@ static struct dvb_usb_properties wt220u_properties = { .num_device_descs = 1, .devices = { - { .name = "WideView WT-220U PenType Receiver (and clones)", + { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", .cold_ids = { &dtt200u_usb_table[2], NULL }, .warm_ids = { &dtt200u_usb_table[3], NULL }, }, @@ -201,9 +200,9 @@ static struct dvb_usb_properties wt220u_properties = { static struct usb_driver dtt200u_usb_driver = { .owner = THIS_MODULE, .name = "dvb_usb_dtt200u", - .probe = dtt200u_usb_probe, + .probe = dtt200u_usb_probe, .disconnect = dvb_usb_device_exit, - .id_table = dtt200u_usb_table, + .id_table = dtt200u_usb_table, }; /* module stuff */ -- GitLab From 47dc3d688d04f06d8ef90a06c48930906fbc4a8c Mon Sep 17 00:00:00 2001 From: Patrick Boettcher <pb@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:47 -0700 Subject: [PATCH 138/563] [PATCH] dvb: usb: core: change dvb_usb_device_init() API Change the init call to optionally return the new dvb_usb_device directly. Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-usb/a800.c | 2 +- drivers/media/dvb/dvb-usb/cxusb.c | 2 +- drivers/media/dvb/dvb-usb/dibusb-mb.c | 6 +++--- drivers/media/dvb/dvb-usb/dibusb-mc.c | 2 +- drivers/media/dvb/dvb-usb/digitv.c | 2 +- drivers/media/dvb/dvb-usb/dtt200u.c | 4 ++-- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 3 +++ drivers/media/dvb/dvb-usb/dvb-usb-init.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb.h | 4 ++-- drivers/media/dvb/dvb-usb/nova-t-usb2.c | 2 +- drivers/media/dvb/dvb-usb/umt-010.c | 2 +- drivers/media/dvb/dvb-usb/vp702x.c | 2 +- drivers/media/dvb/dvb-usb/vp7045.c | 2 +- 13 files changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index f2fcc2f1f8461..e55322ef76b39 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -90,7 +90,7 @@ static struct dvb_usb_properties a800_properties; static int a800_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&a800_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&a800_properties,THIS_MODULE,NULL); } /* do not change the order of the ID table */ diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 9e96a188f1e9a..d2be035140127 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -211,7 +211,7 @@ static struct dvb_usb_properties cxusb_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE,NULL); } static struct usb_device_id cxusb_table [] = { diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index c9f3e90ee25fd..0058505634a0b 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -86,9 +86,9 @@ static struct dvb_usb_properties dibusb2_0b_properties; static int dibusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE) == 0 || - dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE) == 0 || - dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE) == 0) + if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0) return 0; return -EINVAL; diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c index e9dac430f37da..6a0912eab3960 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mc.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c @@ -20,7 +20,7 @@ static struct dvb_usb_properties dibusb_mc_properties; static int dibusb_mc_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&dibusb_mc_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&dibusb_mc_properties,THIS_MODULE,NULL); } /* do not change the order of the ID table */ diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index f70e0be0920ae..24d2bc6ca97bc 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -173,7 +173,7 @@ static struct dvb_usb_properties digitv_properties; static int digitv_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE,NULL); } static struct usb_device_id digitv_table [] = { diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 9d74f48284faf..5aa12ebab34f1 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -98,8 +98,8 @@ static struct dvb_usb_properties wt220u_properties; static int dtt200u_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE) == 0 || - dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE) == 0) + if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0) return 0; return -ENODEV; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 1b978389e4ecb..0818996bf1507 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -27,6 +27,7 @@ #define USB_VID_KWORLD 0xeb2a #define USB_VID_KYE 0x0458 #define USB_VID_MEDION 0x1660 +#define USB_VID_PINNACLE 0x2304 #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 @@ -88,5 +89,7 @@ #define USB_PID_MEDION_MD95700 0x0932 #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f +#define USB_PID_PCTV_200E 0x020e +#define USB_PID_PCTV_400E 0x020f #endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index ea1098a6c7a86..a902059812a2f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -128,7 +128,9 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device /* * USB */ -int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties *props, struct module *owner) + +int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties + *props, struct module *owner,struct dvb_usb_device **du) { struct usb_device *udev = interface_to_usbdev(intf); struct dvb_usb_device *d = NULL; @@ -170,6 +172,9 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties *p usb_set_intfdata(intf, d); + if (du != NULL) + *du = d; + ret = dvb_usb_init(d); } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index a80567caf508a..0e4f1035b0dd5 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -127,7 +127,7 @@ struct dvb_usb_device; * helper functions. * * @urb: describes the kind of USB transfer used for MPEG2-TS-streaming. - * Currently only BULK is implemented + * (BULK or ISOC) * * @num_device_descs: number of struct dvb_usb_device_description in @devices * @devices: array of struct dvb_usb_device_description compatibles with these @@ -310,7 +310,7 @@ struct dvb_usb_device { void *priv; }; -extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_properties *, struct module *); +extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_properties *, struct module *, struct dvb_usb_device **); extern void dvb_usb_device_exit(struct usb_interface *); /* the generic read/write method for device control */ diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c index 258a92bfbcc79..1841a66427bfe 100644 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -144,7 +144,7 @@ static struct dvb_usb_properties nova_t_properties; static int nova_t_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&nova_t_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&nova_t_properties,THIS_MODULE,NULL); } /* do not change the order of the ID table */ diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index 2112ac3cf5e2c..6fd67657c2693 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -77,7 +77,7 @@ static struct dvb_usb_properties umt_properties; static int umt_probe(struct usb_interface *intf, const struct usb_device_id *id) { - if (dvb_usb_device_init(intf,&umt_properties,THIS_MODULE) == 0) + if (dvb_usb_device_init(intf,&umt_properties,THIS_MODULE,NULL) == 0) return 0; return -EINVAL; } diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c index 1f5034ca1152c..de13c04e8e64c 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.c +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -197,7 +197,7 @@ static int vp702x_usb_probe(struct usb_interface *intf, usb_clear_halt(udev,usb_sndctrlpipe(udev,0)); usb_clear_halt(udev,usb_rcvctrlpipe(udev,0)); - return dvb_usb_device_init(intf,&vp702x_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&vp702x_properties,THIS_MODULE,NULL); } static struct usb_device_id vp702x_usb_table [] = { diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 9ac95f54f9fc4..13406a8da2470 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -199,7 +199,7 @@ static struct dvb_usb_properties vp7045_properties; static int vp7045_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&vp7045_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&vp7045_properties,THIS_MODULE,NULL); } static struct usb_device_id vp7045_usb_table [] = { -- GitLab From 115eea4e91049a42d81e5284cbb0f50acab6eb39 Mon Sep 17 00:00:00 2001 From: Svante Olofsson <svante@agentum.com> Date: Fri, 9 Sep 2005 13:02:48 -0700 Subject: [PATCH 139/563] [PATCH] dvb: usb: digitv: support for nxt6000 demod Add support for the NXT6000-based digitv-box. Add .get_tune_settings callback for the NXT6000 to have a min_tune_delay of 500ms. Signed-off-by: Svante Olofsson <svante@agentum.com> Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-usb/digitv.c | 40 ++++++++++++++++----------- drivers/media/dvb/frontends/nxt6000.c | 9 ++++++ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 24d2bc6ca97bc..74545f82eff1d 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -111,31 +111,28 @@ static int digitv_mt352_demod_init(struct dvb_frontend *fe) } static struct mt352_config digitv_mt352_config = { - .demod_address = 0x0, /* ignored by the digitv anyway */ .demod_init = digitv_mt352_demod_init, .pll_set = dvb_usb_pll_set, }; -static struct nxt6000_config digitv_nxt6000_config = { - .demod_address = 0x0, /* ignored by the digitv anyway */ - .clock_inversion = 0x0, +static int digitv_nxt6000_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_device *d = fe->dvb->priv; + u8 b[5]; + dvb_usb_pll_set(fe,fep,b); + return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0); +} - .pll_init = NULL, - .pll_set = NULL, +static struct nxt6000_config digitv_nxt6000_config = { + .clock_inversion = 1, + .pll_set = digitv_nxt6000_pll_set, }; static int digitv_frontend_attach(struct dvb_usb_device *d) { - if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) + if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL || + (d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) return 0; - if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) { - - warn("nxt6000 support is not done yet, in fact you are one of the first " - "person who wants to use this device in Linux. Please report to " - "linux-dvb@linuxtv.org"); - - return 0; - } return -EIO; } @@ -173,7 +170,18 @@ static struct dvb_usb_properties digitv_properties; static int digitv_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE,NULL); + struct dvb_usb_device *d; + int ret; + if ((ret = dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE,&d)) == 0) { + u8 b[4] = { 0 }; + + b[0] = 1; + digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0); + + b[0] = 0; + digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); + } + return ret; } static struct usb_device_id digitv_table [] = { diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index 966de9853d18b..88a57b7911124 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -482,6 +482,7 @@ static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if ((result = nxt6000_set_inversion(state, param->inversion)) < 0) return result; + msleep(500); return 0; } @@ -525,6 +526,12 @@ static int nxt6000_read_signal_strength(struct dvb_frontend* fe, u16* signal_str return 0; } +static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 500; + return 0; +} + static struct dvb_frontend_ops nxt6000_ops; struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, @@ -578,6 +585,8 @@ static struct dvb_frontend_ops nxt6000_ops = { .init = nxt6000_init, + .get_tune_settings = nxt6000_fe_get_tune_settings, + .set_frontend = nxt6000_set_frontend, .read_status = nxt6000_read_status, -- GitLab From 3beab78f8ad5a483fdbdcbb8599fb06da102b8b7 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher <pb@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:50 -0700 Subject: [PATCH 140/563] [PATCH] dvb: usb: white space cleanup white space cleanup Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-usb/vp7045.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 13406a8da2470..0f57abeb6d6bc 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -164,7 +164,6 @@ static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int off return 0; } - static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) { return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR); @@ -256,9 +255,9 @@ static struct dvb_usb_properties vp7045_properties = { static struct usb_driver vp7045_usb_driver = { .owner = THIS_MODULE, .name = "dvb_usb_vp7045", - .probe = vp7045_usb_probe, + .probe = vp7045_usb_probe, .disconnect = dvb_usb_device_exit, - .id_table = vp7045_usb_table, + .id_table = vp7045_usb_table, }; /* module stuff */ -- GitLab From e2efeab26b77061ba5418f4c98c3b3ed100fb608 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher <pb@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:51 -0700 Subject: [PATCH 141/563] [PATCH] dvb: usb: cxusb: fixes for new firmware This patch changes two things: 1) a firmware update made by the vendor, which has to be done in Windows for now, changes the DVB-data-pipe from isochronous to bulk: it fixes the data distortions (and thus the video-distortions) in DVB-T mode; there is no backwards compatibility with the old firmware as it didn't work anyway 2) with the help of Steve Toth some reverse-engineered functionality is now named correctly, thank you Signed-off-by: Patrick Boettcher <pb@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/dvb-usb/cxusb.c | 64 +++++++++++-------------------- drivers/media/dvb/dvb-usb/cxusb.h | 27 ++++++------- 2 files changed, 37 insertions(+), 54 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index d2be035140127..3fe383f4bb4ce 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -48,35 +48,26 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d, return 0; } -/* I2C */ -static void cxusb_set_i2c_path(struct dvb_usb_device *d, enum cxusb_i2c_pathes path) +/* GPIO */ +static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) { struct cxusb_state *st = d->priv; u8 o[2],i; - if (path == st->cur_i2c_path) + if (st->gpio_write_state[GPIO_TUNER] == onoff) return; - o[0] = IOCTL_SET_I2C_PATH; - switch (path) { - case PATH_CX22702: - o[1] = 0; - break; - case PATH_TUNER_OTHER: - o[1] = 1; - break; - default: - err("unkown i2c path"); - return; - } - cxusb_ctrl_msg(d,CMD_IOCTL,o,2,&i,1); + o[0] = GPIO_TUNER; + o[1] = onoff; + cxusb_ctrl_msg(d,CMD_GPIO_WRITE,o,2,&i,1); if (i != 0x01) - deb_info("i2c_path setting failed.\n"); + deb_info("gpio_write failed.\n"); - st->cur_i2c_path = path; + st->gpio_write_state[GPIO_TUNER] = onoff; } +/* I2C */ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); @@ -92,10 +83,10 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) switch (msg[i].addr) { case 0x63: - cxusb_set_i2c_path(d,PATH_CX22702); + cxusb_gpio_tuner(d,0); break; default: - cxusb_set_i2c_path(d,PATH_TUNER_OTHER); + cxusb_gpio_tuner(d,1); break; } @@ -147,16 +138,20 @@ static struct i2c_algorithm cxusb_i2c_algo = { static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) { - return 0; + u8 b = 0; + if (onoff) + return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); + else + return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); } static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) { u8 buf[2] = { 0x03, 0x00 }; if (onoff) - cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0); + cxusb_ctrl_msg(d,CMD_STREAMING_ON, buf, 2, NULL, 0); else - cxusb_ctrl_msg(d,0x37, NULL, 0, NULL, 0); + cxusb_ctrl_msg(d,CMD_STREAMING_OFF, NULL, 0, NULL, 0); return 0; } @@ -182,22 +177,11 @@ static int cxusb_tuner_attach(struct dvb_usb_device *d) static int cxusb_frontend_attach(struct dvb_usb_device *d) { - u8 buf[2] = { 0x03, 0x00 }; - u8 b = 0; - - if (usb_set_interface(d->udev,0,0) < 0) - err("set interface to alts=0 failed"); - - cxusb_ctrl_msg(d,0xde,&b,0,NULL,0); - cxusb_set_i2c_path(d,PATH_TUNER_OTHER); - cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1); - + u8 b; if (usb_set_interface(d->udev,0,6) < 0) err("set interface failed"); - cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0); - cxusb_set_i2c_path(d,PATH_CX22702); - cxusb_ctrl_msg(d,CMD_POWER_ON, NULL, 0, &b, 1); + cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, &b, 1); if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL) return 0; @@ -237,14 +221,12 @@ static struct dvb_usb_properties cxusb_properties = { .generic_bulk_ctrl_endpoint = 0x01, /* parameter for the MPEG2-data transfer */ .urb = { - .type = DVB_USB_ISOC, + .type = DVB_USB_BULK, .count = 5, .endpoint = 0x02, .u = { - .isoc = { - .framesperurb = 32, - .framesize = 940, - .interval = 5, + .bulk = { + .buffersize = 8192, } } }, diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h index 1d79016e31952..135c2a81f5817 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.h +++ b/drivers/media/dvb/dvb-usb/cxusb.h @@ -1,30 +1,31 @@ #ifndef _DVB_USB_CXUSB_H_ #define _DVB_USB_CXUSB_H_ -#define DVB_USB_LOG_PREFIX "digitv" +#define DVB_USB_LOG_PREFIX "cxusb" #include "dvb-usb.h" extern int dvb_usb_cxusb_debug; #define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) /* usb commands - some of it are guesses, don't have a reference yet */ -#define CMD_I2C_WRITE 0x08 -#define CMD_I2C_READ 0x09 +#define CMD_I2C_WRITE 0x08 +#define CMD_I2C_READ 0x09 -#define CMD_IOCTL 0x0e -#define IOCTL_SET_I2C_PATH 0x02 +#define CMD_GPIO_READ 0x0d +#define CMD_GPIO_WRITE 0x0e +#define GPIO_TUNER 0x02 -#define CMD_POWER_OFF 0x50 -#define CMD_POWER_ON 0x51 +#define CMD_POWER_OFF 0xdc +#define CMD_POWER_ON 0xde -enum cxusb_i2c_pathes { - PATH_UNDEF = 0x00, - PATH_CX22702 = 0x01, - PATH_TUNER_OTHER = 0x02, -}; +#define CMD_STREAMING_ON 0x36 +#define CMD_STREAMING_OFF 0x37 + +#define CMD_ANALOG 0x50 +#define CMD_DIGITAL 0x51 struct cxusb_state { - enum cxusb_i2c_pathes cur_i2c_path; + u8 gpio_write_state[3]; }; #endif -- GitLab From 5b5b53452be0b1132cfb8e22fbe5fe43c25140a0 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach <js@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:52 -0700 Subject: [PATCH 142/563] [PATCH] dvb: remove noisy debug print comment out noisy dprintk in dst_get_signal() (why are errors only visible with debug on? this needs to be cleaned up so we can disable debug by default) Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/dst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 07a0b0a968a62..6c34ac9cefdd4 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -928,7 +928,7 @@ static int dst_get_signal(struct dst_state* state) { int retval; u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__); + //dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__); if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { state->decode_lock = state->decode_strength = state->decode_snr = 0; return 0; -- GitLab From 466d725ac8d9c58a5de87f72b4fe066c4bad3d9d Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach <js@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:53 -0700 Subject: [PATCH 143/563] [PATCH] dvb: bt8xx: endianness fix Endianness fix for risc DMA start address setting. (reported by Stefan Haubenthal/Peter Hettkamp) Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/bt878.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 3bfbba3d9dfc2..f29571450038b 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -219,7 +219,7 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, controlreg &= ~0x1f; controlreg |= 0x1b; - btwrite(cpu_to_le32(bt->risc_dma), BT878_ARISC_START); + btwrite(bt->risc_dma, BT878_ARISC_START); /* original int mask had : * 6 2 8 4 0 -- GitLab From 1f15ddd0b79d1722049952b7359533a18a72f106 Mon Sep 17 00:00:00 2001 From: David Johnson <dj@david-web.co.uk> Date: Fri, 9 Sep 2005 13:02:54 -0700 Subject: [PATCH 144/563] [PATCH] dvb: bt8xx: cleanup Indentation fixes and remove unnecessary braces. Signed-off-by: David Johnson <dj@david-web.co.uk> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/dvb-bt8xx.c | 225 ++++++++++++++-------------- 1 file changed, 114 insertions(+), 111 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 6f857c6091f34..b29b0f558c702 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -32,9 +32,7 @@ #include "dvbdev.h" #include "dvb_demux.h" #include "dvb_frontend.h" - #include "dvb-bt8xx.h" - #include "bt878.h" static int debug; @@ -43,9 +41,9 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); #define dprintk( args... ) \ - do { \ + do \ if (debug) printk(KERN_DEBUG args); \ - } while (0) + while (0) static void dvb_bt8xx_task(unsigned long data) { @@ -119,14 +117,12 @@ static struct bt878 __init *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci unsigned int card_nr; /* Hmm, n squared. Hope n is small */ - for (card_nr = 0; card_nr < bt878_num; card_nr++) { + for (card_nr = 0; card_nr < bt878_num; card_nr++) if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev)) return &bt878[card_nr]; - } return NULL; } - static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) { static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 }; @@ -157,13 +153,19 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - if (params->frequency < 542000000) cp = 0xb4; - else if (params->frequency < 771000000) cp = 0xbc; - else cp = 0xf4; + if (params->frequency < 542000000) + cp = 0xb4; + else if (params->frequency < 771000000) + cp = 0xbc; + else + cp = 0xf4; - if (params->frequency == 0) bs = 0x03; - else if (params->frequency < 443250000) bs = 0x02; - else bs = 0x08; + if (params->frequency == 0) + bs = 0x03; + else if (params->frequency < 443250000) + bs = 0x02; + else + bs = 0x08; pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address pllbuf[1] = div >> 8; @@ -175,7 +177,6 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ } static struct mt352_config thomson_dtt7579_config = { - .demod_address = 0x0f, .demod_init = thomson_dtt7579_demod_init, .pll_set = thomson_dtt7579_pll_set, @@ -183,25 +184,26 @@ static struct mt352_config thomson_dtt7579_config = { static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { - u32 freq = params->frequency; - - int i, a, n, pump; - u32 band, pll; + u32 freq = params->frequency; + int i, a, n, pump; + u32 band, pll; - u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, - 1576000,1718000,1856000,2036000,2150000}; - u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, - 0x00102000,0x00104000,0x00108000,0x00110000, - 0x00120000,0x00140000}; + u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, + 1576000,1718000,1856000,2036000,2150000}; + u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, + 0x00102000,0x00104000,0x00108000,0x00110000, + 0x00120000,0x00140000}; -#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ + #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq); /* This is really the bit driving the tuner chip cx24108 */ - if(freq<950000) freq=950000; /* kHz */ - if(freq>2150000) freq=2150000; /* satellite IF is 950..2150MHz */ + if (freq<950000) + freq = 950000; /* kHz */ + else if (freq>2150000) + freq = 2150000; /* satellite IF is 950..2150MHz */ /* decide which VCO to use for the input frequency */ for(i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++); @@ -228,25 +230,22 @@ static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete cx24110_pll_write(fe,0x500c0000); cx24110_pll_write(fe,0x83f1f800); cx24110_pll_write(fe,pll); -/* writereg(client,0x56,0x7f);*/ + //writereg(client,0x56,0x7f); return 0; } static int pinnsat_pll_init(struct dvb_frontend* fe) { - return 0; + return 0; } - static struct cx24110_config pctvsat_config = { - .demod_address = 0x55, .pll_init = pinnsat_pll_init, .pll_set = cx24108_pll_set, }; - static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; @@ -258,15 +257,23 @@ static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_front div = (36000000 + params->frequency + 83333) / 166666; cfg = 0x88; - if (params->frequency < 175000000) cpump = 2; - else if (params->frequency < 390000000) cpump = 1; - else if (params->frequency < 470000000) cpump = 2; - else if (params->frequency < 750000000) cpump = 2; - else cpump = 3; + if (params->frequency < 175000000) + cpump = 2; + else if (params->frequency < 390000000) + cpump = 1; + else if (params->frequency < 470000000) + cpump = 2; + else if (params->frequency < 750000000) + cpump = 2; + else + cpump = 3; - if (params->frequency < 175000000) band_select = 0x0e; - else if (params->frequency < 470000000) band_select = 0x05; - else band_select = 0x03; + if (params->frequency < 175000000) + band_select = 0x0e; + else if (params->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; @@ -285,14 +292,11 @@ static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const s } static struct sp887x_config microtune_mt7202dtf_config = { - .demod_address = 0x70, .pll_set = microtune_mt7202dtf_pll_set, .request_firmware = microtune_mt7202dtf_request_firmware, }; - - static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) { static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; @@ -303,7 +307,6 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); udelay(2000); mt352_write(fe, mt352_reset, sizeof(mt352_reset)); @@ -326,25 +329,43 @@ static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - if (params->frequency < 150000000) cp = 0xB4; - else if (params->frequency < 173000000) cp = 0xBC; - else if (params->frequency < 250000000) cp = 0xB4; - else if (params->frequency < 400000000) cp = 0xBC; - else if (params->frequency < 420000000) cp = 0xF4; - else if (params->frequency < 470000000) cp = 0xFC; - else if (params->frequency < 600000000) cp = 0xBC; - else if (params->frequency < 730000000) cp = 0xF4; - else cp = 0xFC; - - if (params->frequency < 150000000) bs = 0x01; - else if (params->frequency < 173000000) bs = 0x01; - else if (params->frequency < 250000000) bs = 0x02; - else if (params->frequency < 400000000) bs = 0x02; - else if (params->frequency < 420000000) bs = 0x02; - else if (params->frequency < 470000000) bs = 0x02; - else if (params->frequency < 600000000) bs = 0x08; - else if (params->frequency < 730000000) bs = 0x08; - else bs = 0x08; + if (params->frequency < 150000000) + cp = 0xB4; + else if (params->frequency < 173000000) + cp = 0xBC; + else if (params->frequency < 250000000) + cp = 0xB4; + else if (params->frequency < 400000000) + cp = 0xBC; + else if (params->frequency < 420000000) + cp = 0xF4; + else if (params->frequency < 470000000) + cp = 0xFC; + else if (params->frequency < 600000000) + cp = 0xBC; + else if (params->frequency < 730000000) + cp = 0xF4; + else + cp = 0xFC; + + if (params->frequency < 150000000) + bs = 0x01; + else if (params->frequency < 173000000) + bs = 0x01; + else if (params->frequency < 250000000) + bs = 0x02; + else if (params->frequency < 400000000) + bs = 0x02; + else if (params->frequency < 420000000) + bs = 0x02; + else if (params->frequency < 470000000) + bs = 0x02; + else if (params->frequency < 600000000) + bs = 0x08; + else if (params->frequency < 730000000) + bs = 0x08; + else + bs = 0x08; pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address pllbuf[1] = div >> 8; @@ -356,19 +377,15 @@ static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct } static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { - .demod_address = 0x0f, .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, .pll_set = advbt771_samsung_tdtc9251dh0_pll_set, }; - static struct dst_config dst_config = { - .demod_address = 0x55, }; - static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) { struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; @@ -398,10 +415,9 @@ static void or51211_reset(struct dvb_frontend * fe) */ /* reset & PRM1,2&4 are outputs */ int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F); - if (ret != 0) { + if (ret != 0) printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR " "(%i)\n", ret); - } bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */ msleep(20); /* Now set for normal operation */ @@ -417,7 +433,6 @@ static void or51211_sleep(struct dvb_frontend * fe) } static struct or51211_config or51211_config = { - .demod_address = 0x15, .request_firmware = or51211_request_firmware, .setmode = or51211_setmode, @@ -425,7 +440,6 @@ static struct or51211_config or51211_config = { .sleep = or51211_sleep, }; - static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; @@ -454,13 +468,11 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten } static struct nxt6000_config vp3021_alps_tded4_config = { - .demod_address = 0x0a, .clock_inversion = 1, .pll_set = vp3021_alps_tded4_pll_set, }; - static void frontend_init(struct dvb_bt8xx_card *card, u32 type) { int ret; @@ -468,7 +480,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) switch(type) { #ifdef BTTV_DVICO_DVBT_LITE - case BTTV_DVICO_DVBT_LITE: + case BTTV_DVICO_DVBT_LITE: card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter); if (card->fe != NULL) { card->fe->ops->info.frequency_min = 174000000; @@ -479,24 +491,22 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) #endif #ifdef BTTV_TWINHAN_VP3021 - case BTTV_TWINHAN_VP3021: + case BTTV_TWINHAN_VP3021: #else - case BTTV_NEBULA_DIGITV: + case BTTV_NEBULA_DIGITV: #endif card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter); - if (card->fe != NULL) { + if (card->fe != NULL) break; - } break; - case BTTV_AVDVBT_761: + case BTTV_AVDVBT_761: card->fe = sp887x_attach(µtune_mt7202dtf_config, card->i2c_adapter); - if (card->fe != NULL) { + if (card->fe != NULL) break; - } break; - case BTTV_AVDVBT_771: + case BTTV_AVDVBT_771: card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); if (card->fe != NULL) { card->fe->ops->info.frequency_min = 174000000; @@ -505,7 +515,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) } break; - case BTTV_TWINHAN_DST: + case BTTV_TWINHAN_DST: /* DST is not a frontend driver !!! */ state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL); /* Setup the Card */ @@ -522,54 +532,48 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) /* Attach other DST peripherals if any */ /* Conditional Access device */ - if (state->dst_hw_cap & DST_TYPE_HAS_CA) { + if (state->dst_hw_cap & DST_TYPE_HAS_CA) ret = dst_ca_attach(state, &card->dvb_adapter); - } - if (card->fe != NULL) { + + if (card->fe != NULL) break; - } break; - case BTTV_PINNACLESAT: + case BTTV_PINNACLESAT: card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter); - if (card->fe != NULL) { + if (card->fe != NULL) break; - } break; - case BTTV_PC_HDTV: + case BTTV_PC_HDTV: card->fe = or51211_attach(&or51211_config, card->i2c_adapter); - if (card->fe != NULL) { + if (card->fe != NULL) break; - } break; } - if (card->fe == NULL) { + if (card->fe == NULL) printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", card->bt->dev->vendor, card->bt->dev->device, card->bt->dev->subsystem_vendor, card->bt->dev->subsystem_device); - } else { + else if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { printk("dvb-bt8xx: Frontend registration failed!\n"); if (card->fe->ops->release) card->fe->ops->release(card->fe); card->fe = NULL; } - } } static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) { int result; - if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, - THIS_MODULE)) < 0) { + if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) { printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result); return result; - } card->dvb_adapter.priv = card; @@ -664,9 +668,8 @@ static int dvb_bt8xx_probe(struct device *dev) strncpy(card->card_name, sub->core->name, sizeof(sub->core->name)); card->i2c_adapter = &sub->core->i2c_adap; - switch(sub->core->type) - { - case BTTV_PINNACLESAT: + switch(sub->core->type) { + case BTTV_PINNACLESAT: card->gpio_mode = 0x0400c060; /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ @@ -675,7 +678,7 @@ static int dvb_bt8xx_probe(struct device *dev) break; #ifdef BTTV_DVICO_DVBT_LITE - case BTTV_DVICO_DVBT_LITE: + case BTTV_DVICO_DVBT_LITE: #endif card->gpio_mode = 0x0400C060; card->op_sync_orin = 0; @@ -686,25 +689,25 @@ static int dvb_bt8xx_probe(struct device *dev) break; #ifdef BTTV_TWINHAN_VP3021 - case BTTV_TWINHAN_VP3021: + case BTTV_TWINHAN_VP3021: #else - case BTTV_NEBULA_DIGITV: + case BTTV_NEBULA_DIGITV: #endif - case BTTV_AVDVBT_761: + case BTTV_AVDVBT_761: card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); card->op_sync_orin = 0; card->irq_err_ignore = 0; /* A_PWRDN DA_SBR DA_APP (high speed serial) */ break; - case BTTV_AVDVBT_771: //case 0x07711461: + case BTTV_AVDVBT_771: //case 0x07711461: card->gpio_mode = 0x0400402B; card->op_sync_orin = BT878_RISC_SYNC_MASK; card->irq_err_ignore = 0; /* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/ break; - case BTTV_TWINHAN_DST: + case BTTV_TWINHAN_DST: card->gpio_mode = 0x2204f2c; card->op_sync_orin = BT878_RISC_SYNC_MASK; card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR | @@ -722,13 +725,13 @@ static int dvb_bt8xx_probe(struct device *dev) * RISC+FIFO ENABLE */ break; - case BTTV_PC_HDTV: + case BTTV_PC_HDTV: card->gpio_mode = 0x0100EC7B; card->op_sync_orin = 0; card->irq_err_ignore = 0; break; - default: + default: printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n", sub->core->type); kfree(card); @@ -751,7 +754,6 @@ static int dvb_bt8xx_probe(struct device *dev) kfree(card); return -EFAULT; - } init_MUTEX(&card->bt->gpio_lock); @@ -779,7 +781,8 @@ static int dvb_bt8xx_remove(struct device *dev) card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); dvb_dmxdev_release(&card->dmxdev); dvb_dmx_release(&card->demux); - if (card->fe) dvb_unregister_frontend(card->fe); + if (card->fe) + dvb_unregister_frontend(card->fe); dvb_unregister_adapter(&card->dvb_adapter); kfree(card); -- GitLab From 05ade5a5cd32f8393c22fc454b0546df2ed497c5 Mon Sep 17 00:00:00 2001 From: David Johnson <dj@david-web.co.uk> Date: Fri, 9 Sep 2005 13:02:55 -0700 Subject: [PATCH 145/563] [PATCH] dvb: bt8xx: Nebula DigiTV mt352 support Add support for Nebula DigiTV PCI cards with the MT352 frontend. Signed-off-by: David Johnson <dj@david-web.co.uk> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/dvb-bt8xx.c | 141 +++++++++++++++++++++------- 1 file changed, 108 insertions(+), 33 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index b29b0f558c702..514dff36e6ebf 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -45,6 +45,8 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); if (debug) printk(KERN_DEBUG args); \ while (0) +#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + static void dvb_bt8xx_task(unsigned long data) { struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data; @@ -150,7 +152,6 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ unsigned char bs = 0; unsigned char cp = 0; - #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; if (params->frequency < 542000000) @@ -326,7 +327,6 @@ static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct unsigned char bs = 0; unsigned char cp = 0; - #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; if (params->frequency < 150000000) @@ -416,8 +416,7 @@ static void or51211_reset(struct dvb_frontend * fe) /* reset & PRM1,2&4 are outputs */ int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F); if (ret != 0) - printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR " - "(%i)\n", ret); + printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret); bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */ msleep(20); /* Now set for normal operation */ @@ -473,6 +472,80 @@ static struct nxt6000_config vp3021_alps_tded4_config = { .pll_set = vp3021_alps_tded4_pll_set, }; +static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +{ + u32 div; + struct dvb_ofdm_parameters *op = ¶ms->u.ofdm; + + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + pllbuf[0] = 0xc2; + pllbuf[1] = (div >> 8) & 0x7F; + pllbuf[2] = div & 0xFF; + pllbuf[3] = 0x85; + + dprintk("frequency %u, div %u\n", params->frequency, div); + + if (params->frequency < 470000000) + pllbuf[4] = 0x02; + else if (params->frequency > 823000000) + pllbuf[4] = 0x88; + else + pllbuf[4] = 0x08; + + if (op->bandwidth == 8) + pllbuf[4] |= 0x04; + + return 0; +} + +static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) +{ + /* + * Reset the frontend, must be called before trying + * to initialise the MT352 or mt352_attach + * will fail. + * + * Presumably not required for the NXT6000 frontend. + * + */ + + int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08); + if (ret != 0) + printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret); + + /* Pulse the reset line */ + bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ + bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */ + msleep(100); + + bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ +} + +static struct mt352_config digitv_alps_tded4_config = { + .demod_address = 0x0a, + .demod_init = digitv_alps_tded4_demod_init, + .pll_set = digitv_alps_tded4_pll_set, +}; + static void frontend_init(struct dvb_bt8xx_card *card, u32 type) { int ret; @@ -480,42 +553,51 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) switch(type) { #ifdef BTTV_DVICO_DVBT_LITE - case BTTV_DVICO_DVBT_LITE: + case BTTV_DVICO_DVBT_LITE: card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter); if (card->fe != NULL) { card->fe->ops->info.frequency_min = 174000000; card->fe->ops->info.frequency_max = 862000000; - break; } break; #endif #ifdef BTTV_TWINHAN_VP3021 - case BTTV_TWINHAN_VP3021: + case BTTV_TWINHAN_VP3021: #else - case BTTV_NEBULA_DIGITV: + case BTTV_NEBULA_DIGITV: #endif + /* + * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); + * this would be a cleaner solution than trying each frontend in turn. + */ + + /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */ card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter); if (card->fe != NULL) - break; + dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); + + /* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */ + digitv_alps_tded4_reset(card); + card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter); + + if (card->fe != NULL) + dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); break; - case BTTV_AVDVBT_761: + case BTTV_AVDVBT_761: card->fe = sp887x_attach(µtune_mt7202dtf_config, card->i2c_adapter); - if (card->fe != NULL) - break; break; - case BTTV_AVDVBT_771: + case BTTV_AVDVBT_771: card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); if (card->fe != NULL) { card->fe->ops->info.frequency_min = 174000000; card->fe->ops->info.frequency_max = 862000000; - break; } break; - case BTTV_TWINHAN_DST: + case BTTV_TWINHAN_DST: /* DST is not a frontend driver !!! */ state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL); /* Setup the Card */ @@ -534,21 +616,14 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) /* Conditional Access device */ if (state->dst_hw_cap & DST_TYPE_HAS_CA) ret = dst_ca_attach(state, &card->dvb_adapter); - - if (card->fe != NULL) - break; break; - case BTTV_PINNACLESAT: + case BTTV_PINNACLESAT: card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter); - if (card->fe != NULL) - break; break; - case BTTV_PC_HDTV: + case BTTV_PC_HDTV: card->fe = or51211_attach(&or51211_config, card->i2c_adapter); - if (card->fe != NULL) - break; break; } @@ -669,7 +744,7 @@ static int dvb_bt8xx_probe(struct device *dev) card->i2c_adapter = &sub->core->i2c_adap; switch(sub->core->type) { - case BTTV_PINNACLESAT: + case BTTV_PINNACLESAT: card->gpio_mode = 0x0400c060; /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ @@ -678,7 +753,7 @@ static int dvb_bt8xx_probe(struct device *dev) break; #ifdef BTTV_DVICO_DVBT_LITE - case BTTV_DVICO_DVBT_LITE: + case BTTV_DVICO_DVBT_LITE: #endif card->gpio_mode = 0x0400C060; card->op_sync_orin = 0; @@ -689,25 +764,25 @@ static int dvb_bt8xx_probe(struct device *dev) break; #ifdef BTTV_TWINHAN_VP3021 - case BTTV_TWINHAN_VP3021: + case BTTV_TWINHAN_VP3021: #else - case BTTV_NEBULA_DIGITV: + case BTTV_NEBULA_DIGITV: #endif - case BTTV_AVDVBT_761: + case BTTV_AVDVBT_761: card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); card->op_sync_orin = 0; card->irq_err_ignore = 0; /* A_PWRDN DA_SBR DA_APP (high speed serial) */ break; - case BTTV_AVDVBT_771: //case 0x07711461: + case BTTV_AVDVBT_771: //case 0x07711461: card->gpio_mode = 0x0400402B; card->op_sync_orin = BT878_RISC_SYNC_MASK; card->irq_err_ignore = 0; /* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/ break; - case BTTV_TWINHAN_DST: + case BTTV_TWINHAN_DST: card->gpio_mode = 0x2204f2c; card->op_sync_orin = BT878_RISC_SYNC_MASK; card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR | @@ -725,13 +800,13 @@ static int dvb_bt8xx_probe(struct device *dev) * RISC+FIFO ENABLE */ break; - case BTTV_PC_HDTV: + case BTTV_PC_HDTV: card->gpio_mode = 0x0100EC7B; card->op_sync_orin = 0; card->irq_err_ignore = 0; break; - default: + default: printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n", sub->core->type); kfree(card); -- GitLab From f30db067a593aeb3fdd97ec0a3e6399ea566f2ad Mon Sep 17 00:00:00 2001 From: Stuart Auchterlonie <stuarta@squashedfrog.net> Date: Fri, 9 Sep 2005 13:02:56 -0700 Subject: [PATCH 146/563] [PATCH] dvb: nebula DigiTV nxt6000 fix Fix bug in Nebula DigiTV frontend detection for nxt6000. Signed-off-by: Stuart Auchterlonie <stuarta@squashedfrog.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/dvb-bt8xx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 514dff36e6ebf..c5c7672cd5381 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -574,8 +574,10 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */ card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter); - if (card->fe != NULL) + if (card->fe != NULL) { dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); + break; + } /* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */ digitv_alps_tded4_reset(card); -- GitLab From f612c5793449ac653b2f4531696d8e74e771e3d3 Mon Sep 17 00:00:00 2001 From: Manu Abraham <manu@kromtek.com> Date: Fri, 9 Sep 2005 13:02:58 -0700 Subject: [PATCH 147/563] [PATCH] dvb: dst: fix symbol rate setting Make the Symbolrate setting card specific. Signed-off-by: Manu Abraham <manu@kromtek.com> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/dst.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 6c34ac9cefdd4..66e69b8e1a0c4 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -324,12 +324,12 @@ static int dst_set_polarization(struct dst_state *state) { switch (state->voltage) { case SEC_VOLTAGE_13: // vertical - printk("%s: Polarization=[Vertical]\n", __FUNCTION__); + dprintk("%s: Polarization=[Vertical]\n", __FUNCTION__); state->tx_tuna[8] &= ~0x40; //1 break; case SEC_VOLTAGE_18: // horizontal - printk("%s: Polarization=[Horizontal]\n", __FUNCTION__); + dprintk("%s: Polarization=[Horizontal]\n", __FUNCTION__); state->tx_tuna[8] |= 0x40; // 0 break; @@ -344,7 +344,7 @@ static int dst_set_polarization(struct dst_state *state) static int dst_set_freq(struct dst_state *state, u32 freq) { state->frequency = freq; - if (debug > 4) + if (verbose > 4) dprintk("%s: set Frequency %u\n", __FUNCTION__, freq); if (state->dst_type == DST_TYPE_IS_SAT) { @@ -451,7 +451,6 @@ static fe_code_rate_t dst_get_fec(struct dst_state* state) static int dst_set_symbolrate(struct dst_state* state, u32 srate) { - u8 *val; u32 symcalc; u64 sval; @@ -463,7 +462,6 @@ static int dst_set_symbolrate(struct dst_state* state, u32 srate) if (debug > 4) dprintk("%s: set symrate %u\n", __FUNCTION__, srate); srate /= 1000; - val = &state->tx_tuna[0]; if (state->type_flags & DST_TYPE_HAS_SYMDIV) { sval = srate; @@ -474,17 +472,19 @@ static int dst_set_symbolrate(struct dst_state* state, u32 srate) if (debug > 4) dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc); - val[5] = (u8) (symcalc >> 12); - val[6] = (u8) (symcalc >> 4); - val[7] = (u8) (symcalc << 4); + state->tx_tuna[5] = (u8) (symcalc >> 12); + state->tx_tuna[6] = (u8) (symcalc >> 4); + state->tx_tuna[7] = (u8) (symcalc << 4); } else { - val[5] = (u8) (srate >> 16) & 0x7f; - val[6] = (u8) (srate >> 8); - val[7] = (u8) srate; + state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; + state->tx_tuna[6] = (u8) (srate >> 8); + state->tx_tuna[7] = (u8) srate; + } + state->tx_tuna[8] &= ~0x20; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { + if (srate > 8000) + state->tx_tuna[8] |= 0x20; } - val[8] &= ~0x20; - if (srate > 8000) - val[8] |= 0x20; return 0; } -- GitLab From 94b7410c8a2d23fad5937b326a0a9e8c5a876e2d Mon Sep 17 00:00:00 2001 From: Manu Abraham <manu@linuxtv.org> Date: Fri, 9 Sep 2005 13:02:59 -0700 Subject: [PATCH 148/563] [PATCH] dvb: dst: remove unnecessary code Code Simplification: CA PMT object is not parsed in the driver anymore. Signed-off-by: Manu Abraham <manu@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/dst_ca.c | 115 ++++++------------------------- 1 file changed, 20 insertions(+), 95 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index bfaacd5fc20f0..d2e0b1cb39d93 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -260,8 +260,6 @@ static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_s } - - static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg) { u8 i = 0; @@ -298,10 +296,14 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length) { if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) { - hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ - hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ - } - else { + hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ + hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ + } else { + if (length > 247) { + dprintk("%s: Message too long ! *** Bailing Out *** !\n", __FUNCTION__); + return -1; + } + hw_buffer->msg[0] = (length & 0xff) + 7; hw_buffer->msg[1] = 0x40; hw_buffer->msg[2] = 0x03; @@ -309,6 +311,11 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, hw_buffer->msg[4] = 0x03; hw_buffer->msg[5] = length & 0xff; hw_buffer->msg[6] = 0x00; + /* + * Need to compute length for EN50221 section 8.3.2, for the time being + * assuming 8.3.2 is not applicable + */ + memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length); } return 0; } @@ -348,15 +355,6 @@ u32 asn_1_decode(u8 *asn_1_array) return length; } -static int init_buffer(u8 *buffer, u32 length) -{ - u32 i; - for (i = 0; i < length; i++) - buffer[i] = 0; - - return 0; -} - static int debug_string(u8 *msg, u32 length, u32 offset) { u32 i; @@ -369,95 +367,22 @@ static int debug_string(u8 *msg, u32 length, u32 offset) return 0; } -static int copy_string(u8 *destination, u8 *source, u32 dest_offset, u32 source_offset, u32 length) -{ - u32 i; - dprintk("%s: Copying [", __FUNCTION__); - for (i = 0; i < length; i++) { - destination[i + dest_offset] = source[i + source_offset]; - dprintk(" %02x", source[i + source_offset]); - } - dprintk("]\n"); - - return i; -} - -static int modify_4_bits(u8 *message, u32 pos) -{ - message[pos] &= 0x0f; - - return 0; -} - - - static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) { - u32 length = 0, count = 0; - u8 asn_1_words, program_header_length; - u16 program_info_length = 0, es_info_length = 0; - u32 hw_offset = 0, buf_offset = 0, i; - u8 dst_tag_length; + u32 length = 0; + u8 tag_length = 8; length = asn_1_decode(&p_ca_message->msg[3]); dprintk("%s: CA Message length=[%d]\n", __FUNCTION__, length); dprintk("%s: ASN.1 ", __FUNCTION__); - debug_string(&p_ca_message->msg[4], length, 0); // length does not include tag and length + debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */ - init_buffer(hw_buffer->msg, length); + memset(hw_buffer->msg, '\0', length); handle_dst_tag(state, p_ca_message, hw_buffer, length); + put_checksum(hw_buffer->msg, hw_buffer->msg[0]); - hw_offset = 7; - asn_1_words = 1; // just a hack to test, should compute this one - buf_offset = 3; - program_header_length = 6; - dst_tag_length = 7; - -// debug_twinhan_ca_params(state, p_ca_message, hw_buffer, reply, query, length, hw_offset, buf_offset); -// dprintk("%s: Program Header(BUF)", __FUNCTION__); -// debug_string(&p_ca_message->msg[4], program_header_length, 0); -// dprintk("%s: Copying Program header\n", __FUNCTION__); - copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + asn_1_words), program_header_length); - buf_offset += program_header_length, hw_offset += program_header_length; - modify_4_bits(hw_buffer->msg, (hw_offset - 2)); - if (state->type_flags & DST_TYPE_HAS_INC_COUNT) { // workaround - dprintk("%s: Probably an ASIC bug !!!\n", __FUNCTION__); - debug_string(hw_buffer->msg, (hw_offset + program_header_length), 0); - hw_buffer->msg[hw_offset - 1] += 1; - } - -// dprintk("%s: Program Header(HW), Count=[%d]", __FUNCTION__, count); -// debug_string(hw_buffer->msg, hw_offset, 0); - - program_info_length = ((program_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset]; - dprintk("%s: Program info length=[%02x]\n", __FUNCTION__, program_info_length); - if (program_info_length) { - count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + 1), (program_info_length + 1) ); // copy next elem, not current - buf_offset += count, hw_offset += count; -// dprintk("%s: Program level ", __FUNCTION__); -// debug_string(hw_buffer->msg, hw_offset, 0); - } - - buf_offset += 1;// hw_offset += 1; - for (i = buf_offset; i < length; i++) { -// dprintk("%s: Stream Header ", __FUNCTION__); - count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, buf_offset, 5); - modify_4_bits(hw_buffer->msg, (hw_offset + 3)); - - hw_offset += 5, buf_offset += 5, i += 4; -// debug_string(hw_buffer->msg, hw_offset, (hw_offset - 5)); - es_info_length = ((es_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset]; - dprintk("%s: ES info length=[%02x]\n", __FUNCTION__, es_info_length); - if (es_info_length) { - // copy descriptors @ STREAM level - dprintk("%s: Descriptors @ STREAM level...!!! \n", __FUNCTION__); - } - - } - hw_buffer->msg[length + dst_tag_length] = dst_check_sum(hw_buffer->msg, (length + dst_tag_length)); -// dprintk("%s: Total length=[%d], Checksum=[%02x]\n", __FUNCTION__, (length + dst_tag_length), hw_buffer->msg[length + dst_tag_length]); - debug_string(hw_buffer->msg, (length + dst_tag_length + 1), 0); // dst tags also - write_to_8820(state, hw_buffer, (length + dst_tag_length + 1), reply); // checksum + debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */ + write_to_8820(state, hw_buffer, (length + tag_length), reply); return 0; } -- GitLab From a427de6f72bc0d83ebb1d87f9003c5e1009f21cd Mon Sep 17 00:00:00 2001 From: Manu Abraham <manu@linuxtv.org> Date: Fri, 9 Sep 2005 13:03:00 -0700 Subject: [PATCH 149/563] [PATCH] dvb: dst: dprrintk cleanup Code Cleanup: o Remove debug noise o Remove debug module parameter debug level is achieved using the verbosity level o Updated to kernel coding style (case labels should not be indented) Signed-off-by: Manu Abraham <manu@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/dst.c | 649 ++++++++++++--------------- drivers/media/dvb/bt8xx/dst_ca.c | 443 ++++++++---------- drivers/media/dvb/bt8xx/dst_common.h | 4 - 3 files changed, 461 insertions(+), 635 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 66e69b8e1a0c4..39835edba1d96 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1,5 +1,4 @@ /* - Frontend/Card driver for TwinHan DST Frontend Copyright (C) 2003 Jamie Honan Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) @@ -19,7 +18,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -28,31 +26,45 @@ #include <linux/vmalloc.h> #include <linux/delay.h> #include <asm/div64.h> - #include "dvb_frontend.h" #include "dst_priv.h" #include "dst_common.h" - static unsigned int verbose = 1; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); -static unsigned int debug = 1; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug messages, default is 0 (yes)"); - static unsigned int dst_addons; module_param(dst_addons, int, 0644); MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); -#define dprintk if (debug) printk - -#define HAS_LOCK 1 -#define ATTEMPT_TUNE 2 -#define HAS_POWER 4 - -static void dst_packsize(struct dst_state* state, int psize) +#define HAS_LOCK 1 +#define ATTEMPT_TUNE 2 +#define HAS_POWER 4 + +#define DST_ERROR 0 +#define DST_NOTICE 1 +#define DST_INFO 2 +#define DST_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > DST_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ##arg); \ + } \ +} while(0) + + +static void dst_packsize(struct dst_state *state, int psize) { union dst_gpio_packet bits; @@ -60,7 +72,7 @@ static void dst_packsize(struct dst_state* state, int psize) bt878_device_control(state->bt, DST_IG_TS, &bits); } -int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay) +int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay) { union dst_gpio_packet enb; union dst_gpio_packet bits; @@ -68,63 +80,55 @@ int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int enb.enb.mask = mask; enb.enb.enable = enbb; - if (verbose > 4) - dprintk("%s: mask=[%04x], enbb=[%04x], outhigh=[%04x]\n", __FUNCTION__, mask, enbb, outhigh); + dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh); if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { - dprintk("%s: dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)\n", __FUNCTION__, err, mask, enbb); + dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb); return -EREMOTEIO; } udelay(1000); /* because complete disabling means no output, no need to do output packet */ if (enbb == 0) return 0; - if (delay) msleep(10); - bits.outp.mask = enbb; bits.outp.highvals = outhigh; - if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { - dprintk("%s: dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)\n", __FUNCTION__, err, enbb, outhigh); + dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh); return -EREMOTEIO; } + return 0; } EXPORT_SYMBOL(dst_gpio_outb); -int dst_gpio_inb(struct dst_state *state, u8 * result) +int dst_gpio_inb(struct dst_state *state, u8 *result) { union dst_gpio_packet rd_packet; int err; *result = 0; - if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { - dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)\n", err); return -EREMOTEIO; } - *result = (u8) rd_packet.rd.value; + return 0; } EXPORT_SYMBOL(dst_gpio_inb); int rdc_reset_state(struct dst_state *state) { - if (verbose > 1) - dprintk("%s: Resetting state machine\n", __FUNCTION__); - + dprintk(verbose, DST_INFO, 1, "Resetting state machine"); if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); return -1; } - msleep(10); - if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); msleep(10); return -1; } @@ -135,16 +139,14 @@ EXPORT_SYMBOL(rdc_reset_state); int rdc_8820_reset(struct dst_state *state) { - if (verbose > 1) - dprintk("%s: Resetting DST\n", __FUNCTION__); - + dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); return -1; } udelay(1000); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); return -1; } @@ -155,10 +157,11 @@ EXPORT_SYMBOL(rdc_8820_reset); int dst_pio_enable(struct dst_state *state) { if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); return -1; } udelay(1000); + return 0; } EXPORT_SYMBOL(dst_pio_enable); @@ -166,7 +169,7 @@ EXPORT_SYMBOL(dst_pio_enable); int dst_pio_disable(struct dst_state *state) { if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); return -1; } if (state->type_flags & DST_TYPE_HAS_FW_1) @@ -183,19 +186,16 @@ int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) for (i = 0; i < 200; i++) { if (dst_gpio_inb(state, &reply) < 0) { - dprintk("%s: dst_gpio_inb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !"); return -1; } - if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { - if (verbose > 4) - dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i); + dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i); return 1; } msleep(10); } - if (verbose > 1) - dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i); + dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i); return 0; } @@ -203,7 +203,7 @@ EXPORT_SYMBOL(dst_wait_dst_ready); int dst_error_recovery(struct dst_state *state) { - dprintk("%s: Trying to return from previous errors...\n", __FUNCTION__); + dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors."); dst_pio_disable(state); msleep(10); dst_pio_enable(state); @@ -215,7 +215,7 @@ EXPORT_SYMBOL(dst_error_recovery); int dst_error_bailout(struct dst_state *state) { - dprintk("%s: Trying to bailout from previous error...\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error."); rdc_8820_reset(state); dst_pio_disable(state); msleep(10); @@ -224,17 +224,15 @@ int dst_error_bailout(struct dst_state *state) } EXPORT_SYMBOL(dst_error_bailout); - -int dst_comm_init(struct dst_state* state) +int dst_comm_init(struct dst_state *state) { - if (verbose > 1) - dprintk ("%s: Initializing DST..\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Initializing DST."); if ((dst_pio_enable(state)) < 0) { - dprintk("%s: PIO Enable Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed"); return -1; } if ((rdc_reset_state(state)) < 0) { - dprintk("%s: RDC 8820 State RESET Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed."); return -1; } if (state->type_flags & DST_TYPE_HAS_FW_1) @@ -246,36 +244,33 @@ int dst_comm_init(struct dst_state* state) } EXPORT_SYMBOL(dst_comm_init); - int write_dst(struct dst_state *state, u8 *data, u8 len) { struct i2c_msg msg = { - .addr = state->config->demod_address,.flags = 0,.buf = data,.len = len + .addr = state->config->demod_address, + .flags = 0, + .buf = data, + .len = len }; int err; - int cnt; - if (debug && (verbose > 4)) { - u8 i; - if (verbose > 4) { - dprintk("%s writing [ ", __FUNCTION__); - for (i = 0; i < len; i++) - dprintk("%02x ", data[i]); - dprintk("]\n"); - } - } + u8 cnt, i; + + dprintk(verbose, DST_NOTICE, 0, "writing [ "); + for (i = 0; i < len; i++) + dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]); + dprintk(verbose, DST_NOTICE, 0, "]\n"); + for (cnt = 0; cnt < 2; cnt++) { if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - dprintk("%s: _write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]); + dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]); dst_error_recovery(state); continue; } else break; } - if (cnt >= 2) { - if (verbose > 1) - printk("%s: RDC 8820 RESET...\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); dst_error_bailout(state); return -1; @@ -285,36 +280,37 @@ int write_dst(struct dst_state *state, u8 *data, u8 len) } EXPORT_SYMBOL(write_dst); -int read_dst(struct dst_state *state, u8 * ret, u8 len) +int read_dst(struct dst_state *state, u8 *ret, u8 len) { - struct i2c_msg msg = {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = ret,.len = len }; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = ret, + .len = len + }; + int err; int cnt; for (cnt = 0; cnt < 2; cnt++) { if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - - dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]); + dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]); dst_error_recovery(state); - continue; } else break; } if (cnt >= 2) { - if (verbose > 1) - printk("%s: RDC 8820 RESET...\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); dst_error_bailout(state); return -1; } - if (debug && (verbose > 4)) { - dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]); - for (err = 1; err < len; err++) - dprintk(" 0x%x", ret[err]); - if (err > 1) - dprintk("\n"); - } + dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]); + for (err = 1; err < len; err++) + dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]); + if (err > 1) + dprintk(verbose, DST_DEBUG, 0, "\n"); return 0; } @@ -323,19 +319,16 @@ EXPORT_SYMBOL(read_dst); static int dst_set_polarization(struct dst_state *state) { switch (state->voltage) { - case SEC_VOLTAGE_13: // vertical - dprintk("%s: Polarization=[Vertical]\n", __FUNCTION__); - state->tx_tuna[8] &= ~0x40; //1 - break; - - case SEC_VOLTAGE_18: // horizontal - dprintk("%s: Polarization=[Horizontal]\n", __FUNCTION__); - state->tx_tuna[8] |= 0x40; // 0 - break; - - case SEC_VOLTAGE_OFF: - - break; + case SEC_VOLTAGE_13: /* Vertical */ + dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]"); + state->tx_tuna[8] &= ~0x40; + break; + case SEC_VOLTAGE_18: /* Horizontal */ + dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]"); + state->tx_tuna[8] |= 0x40; + break; + case SEC_VOLTAGE_OFF: + break; } return 0; @@ -344,14 +337,12 @@ static int dst_set_polarization(struct dst_state *state) static int dst_set_freq(struct dst_state *state, u32 freq) { state->frequency = freq; - if (verbose > 4) - dprintk("%s: set Frequency %u\n", __FUNCTION__, freq); + dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq); if (state->dst_type == DST_TYPE_IS_SAT) { freq = freq / 1000; if (freq < 950 || freq > 2150) return -EINVAL; - state->tx_tuna[2] = (freq >> 8); state->tx_tuna[3] = (u8) freq; state->tx_tuna[4] = 0x01; @@ -360,27 +351,24 @@ static int dst_set_freq(struct dst_state *state, u32 freq) if (freq < 1531) state->tx_tuna[8] |= 0x04; } - } else if (state->dst_type == DST_TYPE_IS_TERR) { freq = freq / 1000; if (freq < 137000 || freq > 858000) return -EINVAL; - state->tx_tuna[2] = (freq >> 16) & 0xff; state->tx_tuna[3] = (freq >> 8) & 0xff; state->tx_tuna[4] = (u8) freq; - } else if (state->dst_type == DST_TYPE_IS_CABLE) { state->tx_tuna[2] = (freq >> 16) & 0xff; state->tx_tuna[3] = (freq >> 8) & 0xff; state->tx_tuna[4] = (u8) freq; - } else return -EINVAL; + return 0; } -static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth) +static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) { state->bandwidth = bandwidth; @@ -388,90 +376,82 @@ static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth) return 0; switch (bandwidth) { - case BANDWIDTH_6_MHZ: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x06; - else { - state->tx_tuna[6] = 0x06; - state->tx_tuna[7] = 0x00; - } - break; - - case BANDWIDTH_7_MHZ: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x07; - else { - state->tx_tuna[6] = 0x07; - state->tx_tuna[7] = 0x00; - } - break; - - case BANDWIDTH_8_MHZ: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x08; - else { - state->tx_tuna[6] = 0x08; - state->tx_tuna[7] = 0x00; - } - break; - - default: - return -EINVAL; + case BANDWIDTH_6_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x06; + else { + state->tx_tuna[6] = 0x06; + state->tx_tuna[7] = 0x00; + } + break; + case BANDWIDTH_7_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x07; + else { + state->tx_tuna[6] = 0x07; + state->tx_tuna[7] = 0x00; + } + break; + case BANDWIDTH_8_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x08; + else { + state->tx_tuna[6] = 0x08; + state->tx_tuna[7] = 0x00; + } + break; + default: + return -EINVAL; } + return 0; } -static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion) +static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion) { state->inversion = inversion; switch (inversion) { - case INVERSION_OFF: // Inversion = Normal - state->tx_tuna[8] &= ~0x80; - break; - - case INVERSION_ON: - state->tx_tuna[8] |= 0x80; - break; - default: - return -EINVAL; + case INVERSION_OFF: /* Inversion = Normal */ + state->tx_tuna[8] &= ~0x80; + break; + case INVERSION_ON: + state->tx_tuna[8] |= 0x80; + break; + default: + return -EINVAL; } + return 0; } -static int dst_set_fec(struct dst_state* state, fe_code_rate_t fec) +static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec) { state->fec = fec; return 0; } -static fe_code_rate_t dst_get_fec(struct dst_state* state) +static fe_code_rate_t dst_get_fec(struct dst_state *state) { return state->fec; } -static int dst_set_symbolrate(struct dst_state* state, u32 srate) +static int dst_set_symbolrate(struct dst_state *state, u32 srate) { u32 symcalc; u64 sval; state->symbol_rate = srate; - if (state->dst_type == DST_TYPE_IS_TERR) { return 0; } - if (debug > 4) - dprintk("%s: set symrate %u\n", __FUNCTION__, srate); + dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); srate /= 1000; - if (state->type_flags & DST_TYPE_HAS_SYMDIV) { sval = srate; sval <<= 20; do_div(sval, 88000); symcalc = (u32) sval; - - if (debug > 4) - dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc); - + dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); state->tx_tuna[5] = (u8) (symcalc >> 12); state->tx_tuna[6] = (u8) (symcalc >> 4); state->tx_tuna[7] = (u8) (symcalc << 4); @@ -496,32 +476,27 @@ static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulatio state->modulation = modulation; switch (modulation) { - case QAM_16: - state->tx_tuna[8] = 0x10; - break; - - case QAM_32: - state->tx_tuna[8] = 0x20; - break; - - case QAM_64: - state->tx_tuna[8] = 0x40; - break; - - case QAM_128: - state->tx_tuna[8] = 0x80; - break; - - case QAM_256: - state->tx_tuna[8] = 0x00; - break; - - case QPSK: - case QAM_AUTO: - case VSB_8: - case VSB_16: - default: - return -EINVAL; + case QAM_16: + state->tx_tuna[8] = 0x10; + break; + case QAM_32: + state->tx_tuna[8] = 0x20; + break; + case QAM_64: + state->tx_tuna[8] = 0x40; + break; + case QAM_128: + state->tx_tuna[8] = 0x80; + break; + case QAM_256: + state->tx_tuna[8] = 0x00; + break; + case QPSK: + case QAM_AUTO: + case VSB_8: + case VSB_16: + default: + return -EINVAL; } @@ -534,7 +509,7 @@ static fe_modulation_t dst_get_modulation(struct dst_state *state) } -u8 dst_check_sum(u8 * buf, u32 len) +u8 dst_check_sum(u8 *buf, u32 len) { u32 i; u8 val = 0; @@ -549,26 +524,24 @@ EXPORT_SYMBOL(dst_check_sum); static void dst_type_flags_print(u32 type_flags) { - printk("DST type flags :"); + dprintk(verbose, DST_ERROR, 0, "DST type flags :"); if (type_flags & DST_TYPE_HAS_NEWTUNE) - printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE); + dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_NEWTUNE); if (type_flags & DST_TYPE_HAS_TS204) - printk(" 0x%x ts204", DST_TYPE_HAS_TS204); + dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204); if (type_flags & DST_TYPE_HAS_SYMDIV) - printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV); + dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV); if (type_flags & DST_TYPE_HAS_FW_1) - printk(" 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); if (type_flags & DST_TYPE_HAS_FW_2) - printk(" 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); if (type_flags & DST_TYPE_HAS_FW_3) - printk(" 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); -// if ((type_flags & DST_TYPE_HAS_FW_BUILD) && new_fw) - - printk("\n"); + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); + dprintk(verbose, DST_ERROR, 0, "\n"); } -static int dst_type_print (u8 type) +static int dst_type_print(u8 type) { char *otype; switch (type) { @@ -585,10 +558,10 @@ static int dst_type_print (u8 type) break; default: - printk("%s: invalid dst type %d\n", __FUNCTION__, type); + dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); return -EINVAL; } - printk("DST type : %s\n", otype); + dprintk(verbose, DST_INFO, 1, "DST type: %s", otype); return 0; } @@ -772,53 +745,45 @@ static int dst_get_device_id(struct dst_state *state) if (write_dst(state, device_type, FIXED_COMM)) return -1; /* Write failed */ - if ((dst_pio_disable(state)) < 0) return -1; - if (read_dst(state, &reply, GET_ACK)) return -1; /* Read failure */ - if (reply != ACK) { - dprintk("%s: Write not Acknowledged! [Reply=0x%02x]\n", __FUNCTION__, reply); + dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply); return -1; /* Unack'd write */ } - if (!dst_wait_dst_ready(state, DEVICE_INIT)) return -1; /* DST not ready yet */ - if (read_dst(state, state->rxbuffer, FIXED_COMM)) return -1; dst_pio_disable(state); - if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { - dprintk("%s: Checksum failure! \n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Checksum failure!"); return -1; /* Checksum failure */ } - state->rxbuffer[7] = '\0'; - for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE (dst_tlist); i++, p_dst_type++) { + for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) { if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { use_type_flags = p_dst_type->type_flags; use_dst_type = p_dst_type->dst_type; /* Card capabilities */ state->dst_hw_cap = p_dst_type->dst_feature; - printk ("%s: Recognise [%s]\n", __FUNCTION__, p_dst_type->device_id); + dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id); break; } } if (i >= sizeof (dst_tlist) / sizeof (dst_tlist [0])) { - printk("%s: Unable to recognize %s or %s\n", __FUNCTION__, &state->rxbuffer[0], &state->rxbuffer[1]); - printk("%s: please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]); + dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in"); use_dst_type = DST_TYPE_IS_SAT; use_type_flags = DST_TYPE_HAS_SYMDIV; } - dst_type_print(use_dst_type); state->type_flags = use_type_flags; state->dst_type = use_dst_type; @@ -834,7 +799,7 @@ static int dst_get_device_id(struct dst_state *state) static int dst_probe(struct dst_state *state) { if ((rdc_8820_reset(state)) < 0) { - dprintk("%s: RDC 8820 RESET Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); return -1; } if (dst_addons & DST_TYPE_HAS_CA) @@ -843,80 +808,69 @@ static int dst_probe(struct dst_state *state) msleep(100); if ((dst_comm_init(state)) < 0) { - dprintk("%s: DST Initialization Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); return -1; } msleep(100); if (dst_get_device_id(state) < 0) { - dprintk("%s: unknown device.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "unknown device."); return -1; } return 0; } -int dst_command(struct dst_state* state, u8 * data, u8 len) +int dst_command(struct dst_state *state, u8 *data, u8 len) { u8 reply; if ((dst_comm_init(state)) < 0) { - dprintk("%s: DST Communication Initialization Failed.\n", __FUNCTION__); + dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); return -1; } - if (write_dst(state, data, len)) { - if (verbose > 1) - dprintk("%s: Tring to recover.. \n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Tring to recover.. "); if ((dst_error_recovery(state)) < 0) { - dprintk("%s: Recovery Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); return -1; } return -1; } if ((dst_pio_disable(state)) < 0) { - dprintk("%s: PIO Disable Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); return -1; } if (state->type_flags & DST_TYPE_HAS_FW_1) udelay(3000); - if (read_dst(state, &reply, GET_ACK)) { - if (verbose > 1) - dprintk("%s: Trying to recover.. \n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); if ((dst_error_recovery(state)) < 0) { - dprintk("%s: Recovery Failed.\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Recovery Failed."); return -1; } return -1; } - if (reply != ACK) { - dprintk("%s: write not acknowledged 0x%02x \n", __FUNCTION__, reply); + dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); return -1; } if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) return 0; - -// udelay(3000); if (state->type_flags & DST_TYPE_HAS_FW_1) udelay(3000); else udelay(2000); - if (!dst_wait_dst_ready(state, NO_DELAY)) return -1; - if (read_dst(state, state->rxbuffer, FIXED_COMM)) { - if (verbose > 1) - dprintk("%s: Trying to recover.. \n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); if ((dst_error_recovery(state)) < 0) { - dprintk("%s: Recovery failed.\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Recovery failed."); return -1; } return -1; } - if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { - dprintk("%s: checksum failure\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "checksum failure"); return -1; } @@ -924,7 +878,7 @@ int dst_command(struct dst_state* state, u8 * data, u8 len) } EXPORT_SYMBOL(dst_command); -static int dst_get_signal(struct dst_state* state) +static int dst_get_signal(struct dst_state *state) { int retval; u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; @@ -955,13 +909,12 @@ static int dst_get_signal(struct dst_state* state) return 0; } -static int dst_tone_power_cmd(struct dst_state* state) +static int dst_tone_power_cmd(struct dst_state *state) { u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; if (state->dst_type == DST_TYPE_IS_TERR) return 0; - paket[4] = state->tx_tuna[4]; paket[2] = state->tx_tuna[2]; paket[3] = state->tx_tuna[3]; @@ -971,61 +924,53 @@ static int dst_tone_power_cmd(struct dst_state* state) return 0; } -static int dst_get_tuna(struct dst_state* state) +static int dst_get_tuna(struct dst_state *state) { int retval; if ((state->diseq_flags & ATTEMPT_TUNE) == 0) return 0; - state->diseq_flags &= ~(HAS_LOCK); if (!dst_wait_dst_ready(state, NO_DELAY)) return 0; - - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) /* how to get variable length reply ???? */ retval = read_dst(state, state->rx_tuna, 10); - } else { + else retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); - } - if (retval < 0) { - dprintk("%s: read not successful\n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "read not successful"); return 0; } - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { - dprintk("%s: checksum failure?\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "checksum failure ? "); return 0; } } else { if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { - dprintk("%s: checksum failure?\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "checksum failure? "); return 0; } } if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) return 0; state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; - state->decode_lock = 1; state->diseq_flags |= HAS_LOCK; return 1; } -static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage); +static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); -static int dst_write_tuna(struct dvb_frontend* fe) +static int dst_write_tuna(struct dvb_frontend *fe) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; int retval; u8 reply; - if (debug > 4) - dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags); - + dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags); state->decode_freq = 0; state->decode_lock = state->decode_strength = state->decode_snr = 0; if (state->dst_type == DST_TYPE_IS_SAT) { @@ -1035,35 +980,31 @@ static int dst_write_tuna(struct dvb_frontend* fe) state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); if ((dst_comm_init(state)) < 0) { - dprintk("%s: DST Communication initialization failed.\n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); return -1; } - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); retval = write_dst(state, &state->tx_tuna[0], 10); - } else { state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); } if (retval < 0) { dst_pio_disable(state); - dprintk("%s: write not successful\n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "write not successful"); return retval; } - if ((dst_pio_disable(state)) < 0) { - dprintk("%s: DST PIO disable failed !\n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); return -1; } - if ((read_dst(state, &reply, GET_ACK) < 0)) { - dprintk("%s: read verify not successful.\n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); return -1; } if (reply != ACK) { - dprintk("%s: write not acknowledged 0x%02x \n", __FUNCTION__, reply); + dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); return 0; } state->diseq_flags |= ATTEMPT_TUNE; @@ -1085,14 +1026,13 @@ static int dst_write_tuna(struct dvb_frontend* fe) * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 */ -static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; if (state->dst_type != DST_TYPE_IS_SAT) return 0; - if (cmd->msg_len == 0 || cmd->msg_len > 4) return -EINVAL; memcpy(&paket[3], cmd->msg, cmd->msg_len); @@ -1101,65 +1041,61 @@ static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* return 0; } -static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { int need_cmd; - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; state->voltage = voltage; - if (state->dst_type != DST_TYPE_IS_SAT) return 0; need_cmd = 0; - switch (voltage) { - case SEC_VOLTAGE_13: - case SEC_VOLTAGE_18: - if ((state->diseq_flags & HAS_POWER) == 0) - need_cmd = 1; - state->diseq_flags |= HAS_POWER; - state->tx_tuna[4] = 0x01; - break; - case SEC_VOLTAGE_OFF: + switch (voltage) { + case SEC_VOLTAGE_13: + case SEC_VOLTAGE_18: + if ((state->diseq_flags & HAS_POWER) == 0) need_cmd = 1; - state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); - state->tx_tuna[4] = 0x00; - break; - - default: - return -EINVAL; + state->diseq_flags |= HAS_POWER; + state->tx_tuna[4] = 0x01; + break; + case SEC_VOLTAGE_OFF: + need_cmd = 1; + state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); + state->tx_tuna[4] = 0x00; + break; + default: + return -EINVAL; } + if (need_cmd) dst_tone_power_cmd(state); return 0; } -static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; state->tone = tone; - if (state->dst_type != DST_TYPE_IS_SAT) return 0; switch (tone) { - case SEC_TONE_OFF: - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - state->tx_tuna[2] = 0x00; - else - state->tx_tuna[2] = 0xff; - - break; - - case SEC_TONE_ON: - state->tx_tuna[2] = 0x02; - break; + case SEC_TONE_OFF: + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + state->tx_tuna[2] = 0x00; + else + state->tx_tuna[2] = 0xff; + break; - default: - return -EINVAL; + case SEC_TONE_ON: + state->tx_tuna[2] = 0x02; + break; + default: + return -EINVAL; } dst_tone_power_cmd(state); @@ -1172,16 +1108,14 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) if (state->dst_type != DST_TYPE_IS_SAT) return 0; - state->minicmd = minicmd; - switch (minicmd) { - case SEC_MINI_A: - state->tx_tuna[3] = 0x02; - break; - case SEC_MINI_B: - state->tx_tuna[3] = 0xff; - break; + case SEC_MINI_A: + state->tx_tuna[3] = 0x02; + break; + case SEC_MINI_B: + state->tx_tuna[3] = 0xff; + break; } dst_tone_power_cmd(state); @@ -1189,42 +1123,37 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) } -static int dst_init(struct dvb_frontend* fe) +static int dst_init(struct dvb_frontend *fe) { - struct dst_state* state = fe->demodulator_priv; - static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 }; - static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 }; - static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; -// state->inversion = INVERSION_ON; + struct dst_state *state = fe->demodulator_priv; + + static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 }; + static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; + static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + state->inversion = INVERSION_OFF; state->voltage = SEC_VOLTAGE_13; state->tone = SEC_TONE_OFF; - state->symbol_rate = 29473000; - state->fec = FEC_AUTO; state->diseq_flags = 0; state->k22 = 0x02; state->bandwidth = BANDWIDTH_7_MHZ; state->cur_jiff = jiffies; - if (state->dst_type == DST_TYPE_IS_SAT) { - state->frequency = 950000; - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna)); - } else if (state->dst_type == DST_TYPE_IS_TERR) { - state->frequency = 137000000; - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna)); - } else if (state->dst_type == DST_TYPE_IS_CABLE) { - state->frequency = 51000000; - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna)); - } + if (state->dst_type == DST_TYPE_IS_SAT) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_TERR) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_CABLE) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); return 0; } -static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; *status = 0; if (state->diseq_flags & HAS_LOCK) { @@ -1236,9 +1165,9 @@ static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status) return 0; } -static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength) +static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; dst_get_signal(state); *strength = state->decode_strength; @@ -1246,9 +1175,9 @@ static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength) return 0; } -static int dst_read_snr(struct dvb_frontend* fe, u16* snr) +static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; dst_get_signal(state); *snr = state->decode_snr; @@ -1256,28 +1185,24 @@ static int dst_read_snr(struct dvb_frontend* fe, u16* snr) return 0; } -static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; dst_set_freq(state, p->frequency); - if (verbose > 4) - dprintk("Set Frequency=[%d]\n", p->frequency); + dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); -// dst_set_inversion(state, p->inversion); if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->u.qpsk.fec_inner); dst_set_symbolrate(state, p->u.qpsk.symbol_rate); dst_set_polarization(state); - if (verbose > 4) - dprintk("Set Symbolrate=[%d]\n", p->u.qpsk.symbol_rate); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); - } else if (state->dst_type == DST_TYPE_IS_TERR) { + } else if (state->dst_type == DST_TYPE_IS_TERR) dst_set_bandwidth(state, p->u.ofdm.bandwidth); - } else if (state->dst_type == DST_TYPE_IS_CABLE) { + else if (state->dst_type == DST_TYPE_IS_CABLE) { dst_set_fec(state, p->u.qam.fec_inner); dst_set_symbolrate(state, p->u.qam.symbol_rate); dst_set_modulation(state, p->u.qam.modulation); @@ -1287,16 +1212,14 @@ static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet return 0; } -static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; p->frequency = state->decode_freq; -// p->inversion = state->inversion; if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) p->inversion = state->inversion; - p->u.qpsk.symbol_rate = state->symbol_rate; p->u.qpsk.fec_inner = dst_get_fec(state); } else if (state->dst_type == DST_TYPE_IS_TERR) { @@ -1304,16 +1227,15 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet } else if (state->dst_type == DST_TYPE_IS_CABLE) { p->u.qam.symbol_rate = state->symbol_rate; p->u.qam.fec_inner = dst_get_fec(state); -// p->u.qam.modulation = QAM_AUTO; p->u.qam.modulation = dst_get_modulation(state); } return 0; } -static void dst_release(struct dvb_frontend* fe) +static void dst_release(struct dvb_frontend *fe) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; kfree(state); } @@ -1321,9 +1243,8 @@ static struct dvb_frontend_ops dst_dvbt_ops; static struct dvb_frontend_ops dst_dvbs_ops; static struct dvb_frontend_ops dst_dvbc_ops; -struct dst_state* dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) +struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) { - /* check if the ASIC is there */ if (dst_probe(state) < 0) { if (state) @@ -1336,17 +1257,14 @@ struct dst_state* dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad case DST_TYPE_IS_TERR: memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); break; - case DST_TYPE_IS_CABLE: memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); break; - case DST_TYPE_IS_SAT: memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); break; - default: - printk("%s: unknown DST type. please report to the LinuxTV.org DVB mailinglist.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); if (state) kfree(state); @@ -1374,12 +1292,9 @@ static struct dvb_frontend_ops dst_dvbt_ops = { }, .release = dst_release, - .init = dst_init, - .set_frontend = dst_set_frontend, .get_frontend = dst_get_frontend, - .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, .read_snr = dst_read_snr, @@ -1401,16 +1316,12 @@ static struct dvb_frontend_ops dst_dvbs_ops = { }, .release = dst_release, - .init = dst_init, - .set_frontend = dst_set_frontend, .get_frontend = dst_get_frontend, - .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, .read_snr = dst_read_snr, - .diseqc_send_burst = dst_send_burst, .diseqc_send_master_cmd = dst_set_diseqc, .set_voltage = dst_set_voltage, @@ -1432,18 +1343,14 @@ static struct dvb_frontend_ops dst_dvbc_ops = { }, .release = dst_release, - .init = dst_init, - .set_frontend = dst_set_frontend, .get_frontend = dst_get_frontend, - .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, .read_snr = dst_read_snr, }; - MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver"); MODULE_AUTHOR("Jamie Honan, Manu Abraham"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index d2e0b1cb39d93..6776a592045f3 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -18,30 +18,42 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - - #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/string.h> - #include <linux/dvb/ca.h> #include "dvbdev.h" #include "dvb_frontend.h" - #include "dst_ca.h" #include "dst_common.h" +#define DST_CA_ERROR 0 +#define DST_CA_NOTICE 1 +#define DST_CA_INFO 2 +#define DST_CA_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > DST_CA_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_CA_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_CA_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_CA_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ## arg); \ + } \ +} while(0) + + static unsigned int verbose = 5; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); -static unsigned int debug = 1; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug messages, default is 1 (yes)"); - -#define dprintk if (debug) printk - /* Need some more work */ static int ca_set_slot_descr(void) { @@ -61,27 +73,20 @@ static int put_checksum(u8 *check_string, int length) { u8 i = 0, checksum = 0; - if (verbose > 3) { - dprintk("%s: ========================= Checksum calculation ===========================\n", __FUNCTION__); - dprintk("%s: String Length=[0x%02x]\n", __FUNCTION__, length); + dprintk(verbose, DST_CA_DEBUG, 1, " ========================= Checksum calculation ==========================="); + dprintk(verbose, DST_CA_DEBUG, 1, " String Length=[0x%02x]", length); + dprintk(verbose, DST_CA_DEBUG, 1, " String=["); - dprintk("%s: String=[", __FUNCTION__); - } while (i < length) { - if (verbose > 3) - dprintk(" %02x", check_string[i]); + dprintk(verbose, DST_CA_DEBUG, 0, " %02x", check_string[i]); checksum += check_string[i]; i++; } - if (verbose > 3) { - dprintk(" ]\n"); - dprintk("%s: Sum=[%02x]\n", __FUNCTION__, checksum); - } + dprintk(verbose, DST_CA_DEBUG, 0, " ]\n"); + dprintk(verbose, DST_CA_DEBUG, 1, "Sum=[%02x]\n", checksum); check_string[length] = ~checksum + 1; - if (verbose > 3) { - dprintk("%s: Checksum=[%02x]\n", __FUNCTION__, check_string[length]); - dprintk("%s: ==========================================================================\n", __FUNCTION__); - } + dprintk(verbose, DST_CA_DEBUG, 1, " Checksum=[%02x]", check_string[length]); + dprintk(verbose, DST_CA_DEBUG, 1, " =========================================================================="); return 0; } @@ -94,30 +99,26 @@ static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 msleep(65); if (write_dst(state, data, len)) { - dprintk("%s: Write not successful, trying to recover\n", __FUNCTION__); + dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover"); dst_error_recovery(state); return -1; } - if ((dst_pio_disable(state)) < 0) { - dprintk("%s: DST PIO disable failed.\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed."); return -1; } - if (read_dst(state, &reply, GET_ACK) < 0) { - dprintk("%s: Read not successful, trying to recover\n", __FUNCTION__); + dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); dst_error_recovery(state); return -1; } - if (read) { if (! dst_wait_dst_ready(state, LONG_DELAY)) { - dprintk("%s: 8820 not ready\n", __FUNCTION__); + dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready"); return -1; } - if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */ - dprintk("%s: Read not successful, trying to recover\n", __FUNCTION__); + dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); dst_error_recovery(state); return -1; } @@ -133,8 +134,7 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, while (dst_ca_comm_err < RETRIES) { dst_comm_init(state); - if (verbose > 2) - dprintk("%s: Put Command\n", __FUNCTION__); + dprintk(verbose, DST_CA_NOTICE, 1, " Put Command"); if (dst_ci_command(state, data, ca_string, len, read)) { // If error dst_error_recovery(state); dst_ca_comm_err++; // work required here. @@ -153,18 +153,15 @@ static int ca_get_app_info(struct dst_state *state) put_checksum(&command[0], command[0]); if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { - dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); return -1; } - if (verbose > 1) { - dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__); - - dprintk("%s: ================================ CI Module Application Info ======================================\n", __FUNCTION__); - dprintk("%s: Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]\n", - __FUNCTION__, state->messages[7], (state->messages[8] << 8) | state->messages[9], - (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12])); - dprintk("%s: ==================================================================================================\n", __FUNCTION__); - } + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); + dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================"); + dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]", + state->messages[7], (state->messages[8] << 8) | state->messages[9], + (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12])); + dprintk(verbose, DST_CA_INFO, 1, " =================================================================================================="); return 0; } @@ -177,31 +174,26 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, put_checksum(&slot_command[0], slot_command[0]); if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) { - dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); return -1; } - if (verbose > 1) - dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__); + dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !"); /* Will implement the rest soon */ - if (verbose > 1) { - dprintk("%s: Slot cap = [%d]\n", __FUNCTION__, slot_cap[7]); - dprintk("===================================\n"); - for (i = 0; i < 8; i++) - dprintk(" %d", slot_cap[i]); - dprintk("\n"); - } + dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]); + dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); + for (i = 0; i < 8; i++) + dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]); + dprintk(verbose, DST_CA_INFO, 0, "\n"); p_ca_caps->slot_num = 1; p_ca_caps->slot_type = 1; p_ca_caps->descr_num = slot_cap[7]; p_ca_caps->descr_type = 1; - - if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps))) { + if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps))) return -EFAULT; - } return 0; } @@ -222,39 +214,32 @@ static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_s put_checksum(&slot_command[0], 7); if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { - dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); return -1; } - if (verbose > 1) - dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__); + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); /* Will implement the rest soon */ - if (verbose > 1) { - dprintk("%s: Slot info = [%d]\n", __FUNCTION__, slot_info[3]); - dprintk("===================================\n"); - for (i = 0; i < 8; i++) - dprintk(" %d", slot_info[i]); - dprintk("\n"); - } + dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]); + dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); + for (i = 0; i < 8; i++) + dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]); + dprintk(verbose, DST_CA_INFO, 0, "\n"); if (slot_info[4] & 0x80) { p_ca_slot_info->flags = CA_CI_MODULE_PRESENT; p_ca_slot_info->num = 1; p_ca_slot_info->type = CA_CI; - } - else if (slot_info[4] & 0x40) { + } else if (slot_info[4] & 0x40) { p_ca_slot_info->flags = CA_CI_MODULE_READY; p_ca_slot_info->num = 1; p_ca_slot_info->type = CA_CI; - } - else { + } else p_ca_slot_info->flags = 0; - } - if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info))) { + if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info))) return -EFAULT; - } return 0; } @@ -268,24 +253,21 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) return -EFAULT; - if (p_ca_message->msg) { - if (verbose > 3) - dprintk("Message = [%02x %02x %02x]\n", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]); + dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%02x %02x %02x]", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]); for (i = 0; i < 3; i++) { command = command | p_ca_message->msg[i]; if (i < 2) command = command << 8; } - if (verbose > 3) - dprintk("%s:Command=[0x%x]\n", __FUNCTION__, command); + dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); switch (command) { - case CA_APP_INFO: - memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) ) - return -EFAULT; + case CA_APP_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; break; } } @@ -300,10 +282,9 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ } else { if (length > 247) { - dprintk("%s: Message too long ! *** Bailing Out *** !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !"); return -1; } - hw_buffer->msg[0] = (length & 0xff) + 7; hw_buffer->msg[1] = 0x40; hw_buffer->msg[2] = 0x03; @@ -324,13 +305,12 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) { if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { - dprintk("%s: DST-CI Command failed.\n", __FUNCTION__); - dprintk("%s: Resetting DST.\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed."); + dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST."); rdc_reset_state(state); return -1; } - if (verbose > 2) - dprintk("%s: DST-CI Command succes.\n", __FUNCTION__); + dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes."); return 0; } @@ -341,15 +321,15 @@ u32 asn_1_decode(u8 *asn_1_array) u32 length = 0; length_field = asn_1_array[0]; - dprintk("%s: Length field=[%02x]\n", __FUNCTION__, length_field); + dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field); if (length_field < 0x80) { length = length_field & 0x7f; - dprintk("%s: Length=[%02x]\n", __FUNCTION__, length); + dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length); } else { word_count = length_field & 0x7f; for (count = 0; count < word_count; count++) { length = (length | asn_1_array[count + 1]) << 8; - dprintk("%s: Length=[%04x]\n", __FUNCTION__, length); + dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length); } } return length; @@ -359,10 +339,10 @@ static int debug_string(u8 *msg, u32 length, u32 offset) { u32 i; - dprintk(" String=[ "); + dprintk(verbose, DST_CA_DEBUG, 0, " String=[ "); for (i = offset; i < length; i++) - dprintk("%02x ", msg[i]); - dprintk("]\n"); + dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]); + dprintk(verbose, DST_CA_DEBUG, 0, "]\n"); return 0; } @@ -373,8 +353,7 @@ static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, stru u8 tag_length = 8; length = asn_1_decode(&p_ca_message->msg[3]); - dprintk("%s: CA Message length=[%d]\n", __FUNCTION__, length); - dprintk("%s: ASN.1 ", __FUNCTION__); + dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length); debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */ memset(hw_buffer->msg, '\0', length); @@ -396,26 +375,24 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message /* Do test board */ /* Not there yet but soon */ - /* CA PMT Reply capable */ if (ca_pmt_reply_test) { if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) { - dprintk("%s: ca_set_pmt.. failed !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); return -1; } /* Process CA PMT Reply */ /* will implement soon */ - dprintk("%s: Not there yet\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Not there yet"); } /* CA PMT Reply not capable */ if (!ca_pmt_reply_test) { if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) { - dprintk("%s: ca_set_pmt.. failed !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); return -1; } - if (verbose > 3) - dprintk("%s: ca_set_pmt.. success !\n", __FUNCTION__); + dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !"); /* put a dummy message */ } @@ -431,11 +408,10 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer; if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - dprintk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); return -ENOMEM; } - if (verbose > 3) - dprintk("%s\n", __FUNCTION__); + dprintk(verbose, DST_CA_DEBUG, 1, " "); if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) return -EFAULT; @@ -450,51 +426,35 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, if (i < 2) command = command << 8; } - if (verbose > 3) - dprintk("%s:Command=[0x%x]\n", __FUNCTION__, command); + dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); switch (command) { - case CA_PMT: - if (verbose > 3) -// dprintk("Command = SEND_CA_PMT\n"); - dprintk("Command = SEND_CA_PMT\n"); -// if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started - dprintk("%s: -->CA_PMT Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 3) - dprintk("%s: -->CA_PMT Success !\n", __FUNCTION__); -// retval = dummy_set_pmt(state, p_ca_message, hw_buffer, 0, 0); - - break; - - case CA_PMT_REPLY: - if (verbose > 3) - dprintk("Command = CA_PMT_REPLY\n"); - /* Have to handle the 2 basic types of cards here */ - if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { - dprintk("%s: -->CA_PMT_REPLY Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 3) - dprintk("%s: -->CA_PMT_REPLY Success !\n", __FUNCTION__); - - /* Certain boards do behave different ? */ -// retval = ca_set_pmt(state, p_ca_message, hw_buffer, 1, 1); - - case CA_APP_INFO_ENQUIRY: // only for debugging - if (verbose > 3) - dprintk("%s: Getting Cam Application information\n", __FUNCTION__); - - if ((ca_get_app_info(state)) < 0) { - dprintk("%s: -->CA_APP_INFO_ENQUIRY Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 3) - dprintk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__); - - break; + case CA_PMT: + dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); + break; + case CA_PMT_REPLY: + dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); + /* Have to handle the 2 basic types of cards here */ + if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); + break; + case CA_APP_INFO_ENQUIRY: // only for debugging + dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); + + if ((ca_get_app_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); + break; } } return 0; @@ -509,121 +469,88 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct ca_msg *p_ca_message; if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - dprintk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); return -ENOMEM; } - if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) { - dprintk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); return -ENOMEM; } - if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) { - dprintk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); return -ENOMEM; } - /* We have now only the standard ioctl's, the driver is upposed to handle internals. */ switch (cmd) { - case CA_SEND_MSG: - if (verbose > 1) - dprintk("%s: Sending message\n", __FUNCTION__); - if ((ca_send_message(state, p_ca_message, arg)) < 0) { - dprintk("%s: -->CA_SEND_MSG Failed !\n", __FUNCTION__); - return -1; - } - - break; - - case CA_GET_MSG: - if (verbose > 1) - dprintk("%s: Getting message\n", __FUNCTION__); - if ((ca_get_message(state, p_ca_message, arg)) < 0) { - dprintk("%s: -->CA_GET_MSG Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_GET_MSG Success !\n", __FUNCTION__); - - break; - - case CA_RESET: - if (verbose > 1) - dprintk("%s: Resetting DST\n", __FUNCTION__); - dst_error_bailout(state); - msleep(4000); - - break; - - case CA_GET_SLOT_INFO: - if (verbose > 1) - dprintk("%s: Getting Slot info\n", __FUNCTION__); - if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { - dprintk("%s: -->CA_GET_SLOT_INFO Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_GET_SLOT_INFO Success !\n", __FUNCTION__); - - break; - - case CA_GET_CAP: - if (verbose > 1) - dprintk("%s: Getting Slot capabilities\n", __FUNCTION__); - if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { - dprintk("%s: -->CA_GET_CAP Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_GET_CAP Success !\n", __FUNCTION__); - - break; - - case CA_GET_DESCR_INFO: - if (verbose > 1) - dprintk("%s: Getting descrambler description\n", __FUNCTION__); - if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { - dprintk("%s: -->CA_GET_DESCR_INFO Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_GET_DESCR_INFO Success !\n", __FUNCTION__); - - break; - - case CA_SET_DESCR: - if (verbose > 1) - dprintk("%s: Setting descrambler\n", __FUNCTION__); - if ((ca_set_slot_descr()) < 0) { - dprintk("%s: -->CA_SET_DESCR Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_SET_DESCR Success !\n", __FUNCTION__); - - break; - - case CA_SET_PID: - if (verbose > 1) - dprintk("%s: Setting PID\n", __FUNCTION__); - if ((ca_set_pid()) < 0) { - dprintk("%s: -->CA_SET_PID Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_SET_PID Success !\n", __FUNCTION__); - - default: - return -EOPNOTSUPP; - }; + case CA_SEND_MSG: + dprintk(verbose, DST_CA_INFO, 1, " Sending message"); + if ((ca_send_message(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !"); + return -1; + } + break; + case CA_GET_MSG: + dprintk(verbose, DST_CA_INFO, 1, " Getting message"); + if ((ca_get_message(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !"); + break; + case CA_RESET: + dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST"); + dst_error_bailout(state); + msleep(4000); + break; + case CA_GET_SLOT_INFO: + dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info"); + if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !"); + break; + case CA_GET_CAP: + dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities"); + if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !"); + break; + case CA_GET_DESCR_INFO: + dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description"); + if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !"); + break; + case CA_SET_DESCR: + dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler"); + if ((ca_set_slot_descr()) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !"); + break; + case CA_SET_PID: + dprintk(verbose, DST_CA_INFO, 1, " Setting PID"); + if ((ca_set_pid()) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); + default: + return -EOPNOTSUPP; + }; return 0; } static int dst_ca_open(struct inode *inode, struct file *file) { - if (verbose > 4) - dprintk("%s:Device opened [%p]\n", __FUNCTION__, file); + dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file); try_module_get(THIS_MODULE); return 0; @@ -631,27 +558,24 @@ static int dst_ca_open(struct inode *inode, struct file *file) static int dst_ca_release(struct inode *inode, struct file *file) { - if (verbose > 4) - dprintk("%s:Device closed.\n", __FUNCTION__); + dprintk(verbose, DST_CA_DEBUG, 1, " Device closed."); module_put(THIS_MODULE); return 0; } -static int dst_ca_read(struct file *file, char __user * buffer, size_t length, loff_t * offset) +static int dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { int bytes_read = 0; - if (verbose > 4) - dprintk("%s:Device read.\n", __FUNCTION__); + dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); return bytes_read; } -static int dst_ca_write(struct file *file, const char __user * buffer, size_t length, loff_t * offset) +static int dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) { - if (verbose > 4) - dprintk("%s:Device write.\n", __FUNCTION__); + dprintk(verbose, DST_CA_DEBUG, 1, " Device write."); return 0; } @@ -676,8 +600,7 @@ static struct dvb_device dvbdev_ca = { int dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter) { struct dvb_device *dvbdev; - if (verbose > 4) - dprintk("%s:registering DST-CA device\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device"); dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA); return 0; } diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index ef532a6aceaa3..c0ee0b197bb82 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -61,7 +61,6 @@ #define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */ #define DST_TYPE_HAS_SESSION 128 - #define RDC_8820_PIO_0_DISABLE 0 #define RDC_8820_PIO_0_ENABLE 1 #define RDC_8820_INT 2 @@ -124,15 +123,12 @@ struct dst_types { u32 dst_feature; }; - - struct dst_config { /* the ASIC i2c address */ u8 demod_address; }; - int rdc_reset_state(struct dst_state *state); int rdc_8820_reset(struct dst_state *state); -- GitLab From 62121b1f9e25377ff50121f8c34a4aa92c47f465 Mon Sep 17 00:00:00 2001 From: Manu Abraham <manu@linuxtv.org> Date: Fri, 9 Sep 2005 13:03:01 -0700 Subject: [PATCH 150/563] [PATCH] dvb: dst: identify boards Identify board properly: Add functions to retrieve MAC Address, FW details, Card type and Vendor Information. Signed-off-by: Manu Abraham <manu@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/dst.c | 89 +++++++++++++++++++++++++++- drivers/media/dvb/bt8xx/dst_common.h | 4 ++ 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 39835edba1d96..eef34481d535f 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -673,7 +673,7 @@ struct dst_types dst_tlist[] = { .offset = 1, .dst_type = DST_TYPE_IS_CABLE, .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1 - | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, + | DST_TYPE_HAS_FW_2, .dst_feature = DST_TYPE_HAS_CA }, @@ -681,7 +681,7 @@ struct dst_types dst_tlist[] = { .device_id = "DCTNEW", .offset = 1, .dst_type = DST_TYPE_IS_CABLE, - .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3, + .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD, .dst_feature = 0 }, @@ -689,7 +689,7 @@ struct dst_types dst_tlist[] = { .device_id = "DTT-CI", .offset = 1, .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, .dst_feature = 0 }, @@ -729,6 +729,71 @@ struct dst_types dst_tlist[] = { }; +static int dst_get_mac(struct dst_state *state) +{ + u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_mac[7] = dst_check_sum(get_mac, 7); + if (dst_command(state, get_mac, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->mac_address, '\0', 8); + memcpy(&state->mac_address, &state->rxbuffer, 6); + dprintk(verbose, DST_ERROR, 1, "MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]", + state->mac_address[0], state->mac_address[1], state->mac_address[2], + state->mac_address[4], state->mac_address[5], state->mac_address[6]); + + return 0; +} + +static int dst_fw_ver(struct dst_state *state) +{ + u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_ver[7] = dst_check_sum(get_ver, 7); + if (dst_command(state, get_ver, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->fw_version, '\0', 8); + memcpy(&state->fw_version, &state->rxbuffer, 8); + dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x", + state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, + state->fw_version[1], + state->fw_version[5], state->fw_version[6], + state->fw_version[4], state->fw_version[3], state->fw_version[2]); + + return 0; +} + +static int dst_card_type(struct dst_state *state) +{ + u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_type[7] = dst_check_sum(get_type, 7); + if (dst_command(state, get_type, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->card_info, '\0', 8); + memcpy(&state->card_info, &state->rxbuffer, 8); + dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); + + return 0; +} + +static int dst_get_vendor(struct dst_state *state) +{ + u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_vendor[7] = dst_check_sum(get_vendor, 7); + if (dst_command(state, get_vendor, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->vendor, '\0', 8); + memcpy(&state->vendor, &state->rxbuffer, 8); + dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); + + return 0; +} static int dst_get_device_id(struct dst_state *state) { @@ -816,6 +881,24 @@ static int dst_probe(struct dst_state *state) dprintk(verbose, DST_ERROR, 1, "unknown device."); return -1; } + if (dst_get_mac(state) < 0) { + dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); + return 0; + } + if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { + if (dst_fw_ver(state) < 0) { + dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); + return 0; + } + if (dst_card_type(state) < 0) { + dprintk(verbose, DST_INFO, 1, "Card: Unsupported command"); + return 0; + } + if (dst_get_vendor(state) < 0) { + dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command"); + return 0; + } + } return 0; } diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index c0ee0b197bb82..3281a6ca3685d 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -113,6 +113,10 @@ struct dst_state { fe_sec_mini_cmd_t minicmd; fe_modulation_t modulation; u8 messages[256]; + u8 mac_address[8]; + u8 fw_version[8]; + u8 card_info[8]; + u8 vendor[8]; }; struct dst_types { -- GitLab From 62867429d0d79e47e19ceedc3133efe74993932f Mon Sep 17 00:00:00 2001 From: Manu Abraham <manu@linuxtv.org> Date: Fri, 9 Sep 2005 13:03:02 -0700 Subject: [PATCH 151/563] [PATCH] dvb: dst: fix DVB-C tuning Fix BUG in DVB-C frequency setting. Thanks to Peng Cao <caopeng75@gmail.com> Signed-off-by: Manu Abraham <manu@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/bt8xx/dst.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index eef34481d535f..34a837a1abf4f 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -359,6 +359,7 @@ static int dst_set_freq(struct dst_state *state, u32 freq) state->tx_tuna[3] = (freq >> 8) & 0xff; state->tx_tuna[4] = (u8) freq; } else if (state->dst_type == DST_TYPE_IS_CABLE) { + freq = freq / 1000; state->tx_tuna[2] = (freq >> 16) & 0xff; state->tx_tuna[3] = (freq >> 8) & 0xff; state->tx_tuna[4] = (u8) freq; -- GitLab From 9dea88514c476d303f59e19b27ef26bb52dc193a Mon Sep 17 00:00:00 2001 From: Manu Abraham <manu@linuxtv.org> Date: Fri, 9 Sep 2005 13:03:03 -0700 Subject: [PATCH 152/563] [PATCH] dvb: dst: ci doc update Updated documentation Signed-off-by: Manu Abraham <manu@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/dvb/ci.txt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Documentation/dvb/ci.txt b/Documentation/dvb/ci.txt index 62e0701b542af..95f0e73b2135a 100644 --- a/Documentation/dvb/ci.txt +++ b/Documentation/dvb/ci.txt @@ -23,7 +23,6 @@ This application requires the following to function properly as of now. eg: $ szap -c channels.conf -r "TMC" -x (b) a channels.conf containing a valid PMT PID - eg: TMC:11996:h:0:27500:278:512:650:321 here 278 is a valid PMT PID. the rest of the values are the @@ -31,13 +30,7 @@ This application requires the following to function properly as of now. (c) after running a szap, you have to run ca_zap, for the descrambler to function, - - eg: $ ca_zap patched_channels.conf "TMC" - - The patched means a patch to apply to scan, such that scan can - generate a channels.conf_with pmt, which has this PMT PID info - (NOTE: szap cannot use this channels.conf with the PMT_PID) - + eg: $ ca_zap channels.conf "TMC" (d) Hopeflly Enjoy your favourite subscribed channel as you do with a FTA card. -- GitLab From 2d6e7322b5f63d62ec8785c5fbf469c9a233baff Mon Sep 17 00:00:00 2001 From: Manu Abraham <manu@linuxtv.org> Date: Fri, 9 Sep 2005 13:03:04 -0700 Subject: [PATCH 153/563] [PATCH] dvb: dst: Updated Documentation Updated Documentation Signed-off-by: Manu Abraham <manu@linuxtv.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/dvb/bt8xx.txt | 89 ++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt index 4b8c326c6aac9..cb63b7a93c82f 100644 --- a/Documentation/dvb/bt8xx.txt +++ b/Documentation/dvb/bt8xx.txt @@ -1,55 +1,74 @@ -How to get the Nebula Electronics DigiTV, Pinnacle PCTV Sat, Twinhan DST + clones working -========================================================================================= +How to get the Nebula, PCTV and Twinhan DST cards working +========================================================= -1) General information -====================== +This class of cards has a bt878a as the PCI interface, and +require the bttv driver. -This class of cards has a bt878a chip as the PCI interface. -The different card drivers require the bttv driver to provide the means -to access the i2c bus and the gpio pins of the bt8xx chipset. +Please pay close attention to the warning about the bttv module +options below for the DST card. -2) Compilation rules for Kernel >= 2.6.12 -========================================= +1) General informations +======================= -Enable the following options: +These drivers require the bttv driver to provide the means to access +the i2c bus and the gpio pins of the bt8xx chipset. +Because of this, you need to enable "Device drivers" => "Multimedia devices" - => "Video For Linux" => "BT848 Video For Linux" + => "Video For Linux" => "BT848 Video For Linux" + +Furthermore you need to enable "Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" - => "DVB for Linux" "DVB Core Support" "BT8xx based PCI cards" + => "DVB for Linux" "DVB Core Support" "BT8xx based PCI cards" -3) Loading Modules, described by two approaches -=============================================== +2) Loading Modules +================== In general you need to load the bttv driver, which will handle the gpio and -i2c communication for us, plus the common dvb-bt8xx device driver, -which is called the backend. -The frontends for Nebula DigiTV (nxt6000), Pinnacle PCTV Sat (cx24110), -TwinHan DST + clones (dst and dst-ca) are loaded automatically by the backend. -For further details about TwinHan DST + clones see /Documentation/dvb/ci.txt. +i2c communication for us, plus the common dvb-bt8xx device driver. +The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and +TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver. -3a) The manual approach ------------------------ +3a) Nebula / Pinnacle PCTV +-------------------------- -Loading modules: -modprobe bttv -modprobe dvb-bt8xx + $ modprobe bttv (normally bttv is being loaded automatically by kmod) + $ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading) -Unloading modules: -modprobe -r dvb-bt8xx -modprobe -r bttv -3b) The automatic approach +3b) TwinHan and Clones -------------------------- -If not already done by installation, place a line either in -/etc/modules.conf or in /etc/modprobe.conf containing this text: -alias char-major-81 bttv + $ modprobe bttv i2c_hw=1 card=0x71 + $ modprobe dvb-bt8xx + $ modprobe dst + +The value 0x71 will override the PCI type detection for dvb-bt8xx, +which is necessary for TwinHan cards. + +If you're having an older card (blue color circuit) and card=0x71 locks +your machine, try using 0x68, too. If that does not work, ask on the +mailing list. + +The DST module takes a couple of useful parameters. + +verbose takes values 0 to 4. These values control the verbosity level, +and can be used to debug also. + +verbose=0 means complete disabling of messages + 1 only error messages are displayed + 2 notifications are also displayed + 3 informational messages are also displayed + 4 debug setting + +dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card. +0x20 means it has a Conditional Access slot. + +The autodected values are determined bythe cards 'response +string' which you can see in your logs e.g. -Then place a line in /etc/modules containing this text: -dvb-bt8xx +dst_get_device_id: Recognise [DSTMCI] -Reboot your system and have fun! -- -Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham, Uwe Bugla +Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham -- GitLab From 6d78933c291bd0b6292e2c631e2f5e346c14d3fa Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach <js@linuxtv.org> Date: Fri, 9 Sep 2005 13:03:05 -0700 Subject: [PATCH 154/563] [PATCH] dvb: cinergyT2: remote control fixes IR RC fixes: - EVIOCSKEYCODE is not supported by this driver, fix potential crash when it is used by not setting rc_input_dev->keycodesize - fix key repeat handling (hopefully) - reduce default poll internal to 50msec (necessary for key repeat handling) Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/cinergyT2/Kconfig | 2 +- drivers/media/dvb/cinergyT2/cinergyT2.c | 93 +++++++++++++++---------- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig index 226714085f58d..7cf4c4a888ec6 100644 --- a/drivers/media/dvb/cinergyT2/Kconfig +++ b/drivers/media/dvb/cinergyT2/Kconfig @@ -77,7 +77,7 @@ config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE config DVB_CINERGYT2_RC_QUERY_INTERVAL int "Infrared Remote Controller update interval [milliseconds]" depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE - default "100" + default "50" help If you have a very fast-repeating remote control you can try lower values, for normal consumer receivers the default value should be diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index c52e9d5c3d96d..6db0929ef53db 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -35,7 +35,6 @@ #include "dvb_demux.h" #include "dvb_net.h" - #ifdef CONFIG_DVB_CINERGYT2_TUNING #define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT) #define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE) @@ -48,7 +47,7 @@ #define STREAM_URB_COUNT (32) #define STREAM_BUF_SIZE (512) /* bytes */ #define ENABLE_RC (1) - #define RC_QUERY_INTERVAL (100) /* milliseconds */ + #define RC_QUERY_INTERVAL (50) /* milliseconds */ #define QUERY_INTERVAL (333) /* milliseconds */ #endif @@ -141,6 +140,8 @@ struct cinergyt2 { struct input_dev rc_input_dev; struct work_struct rc_query_work; int rc_input_event; + u32 rc_last_code; + unsigned long last_event_jiffies; #endif }; @@ -155,7 +156,7 @@ struct cinergyt2_rc_event { uint32_t value; } __attribute__((packed)); -static const uint32_t rc_keys [] = { +static const uint32_t rc_keys[] = { CINERGYT2_RC_EVENT_TYPE_NEC, 0xfe01eb04, KEY_POWER, CINERGYT2_RC_EVENT_TYPE_NEC, 0xfd02eb04, KEY_1, CINERGYT2_RC_EVENT_TYPE_NEC, 0xfc03eb04, KEY_2, @@ -684,52 +685,68 @@ static struct dvb_device cinergyt2_fe_template = { #ifdef ENABLE_RC static void cinergyt2_query_rc (void *data) { - struct cinergyt2 *cinergyt2 = (struct cinergyt2 *) data; - char buf [1] = { CINERGYT2_EP1_GET_RC_EVENTS }; + struct cinergyt2 *cinergyt2 = data; + char buf[1] = { CINERGYT2_EP1_GET_RC_EVENTS }; struct cinergyt2_rc_event rc_events[12]; - int n, len; + int n, len, i; if (down_interruptible(&cinergyt2->sem)) return; len = cinergyt2_command(cinergyt2, buf, sizeof(buf), - (char *) rc_events, sizeof(rc_events)); - - for (n=0; len>0 && n<(len/sizeof(rc_events[0])); n++) { - int i; + (char *) rc_events, sizeof(rc_events)); + if (len < 0) + goto out; + if (len == 0) { + if (time_after(jiffies, cinergyt2->last_event_jiffies + + msecs_to_jiffies(150))) { + /* stop key repeat */ + if (cinergyt2->rc_input_event != KEY_MAX) { + dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event); + input_report_key(&cinergyt2->rc_input_dev, + cinergyt2->rc_input_event, 0); + cinergyt2->rc_input_event = KEY_MAX; + } + cinergyt2->rc_last_code = ~0; + } + goto out; + } + cinergyt2->last_event_jiffies = jiffies; -/* dprintk(1,"rc_events[%d].value = %x, type=%x\n",n,le32_to_cpu(rc_events[n].value),rc_events[n].type);*/ + for (n = 0; n < (len / sizeof(rc_events[0])); n++) { + dprintk(1, "rc_events[%d].value = %x, type=%x\n", + n, le32_to_cpu(rc_events[n].value), rc_events[n].type); if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC && - rc_events[n].value == ~0) - { - /** - * keyrepeat bit. If we would handle this properly - * we would need to emit down events as long the - * keyrepeat goes, a up event if no further - * repeat bits occur. Would need a timer to implement - * and no other driver does this, so we simply - * emit the last key up/down sequence again. - */ + rc_events[n].value == ~0) { + /* keyrepeat bit -> just repeat last rc_input_event */ } else { cinergyt2->rc_input_event = KEY_MAX; - for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3) { - if (rc_keys[i+0] == rc_events[n].type && - rc_keys[i+1] == le32_to_cpu(rc_events[n].value)) - { - cinergyt2->rc_input_event = rc_keys[i+2]; + for (i = 0; i < sizeof(rc_keys) / sizeof(rc_keys[0]); i += 3) { + if (rc_keys[i + 0] == rc_events[n].type && + rc_keys[i + 1] == le32_to_cpu(rc_events[n].value)) { + cinergyt2->rc_input_event = rc_keys[i + 2]; break; } } } if (cinergyt2->rc_input_event != KEY_MAX) { - input_report_key(&cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 1); - input_report_key(&cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0); - input_sync(&cinergyt2->rc_input_dev); + if (rc_events[n].value == cinergyt2->rc_last_code && + cinergyt2->rc_last_code != ~0) { + /* emit a key-up so the double event is recognized */ + dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event); + input_report_key(&cinergyt2->rc_input_dev, + cinergyt2->rc_input_event, 0); + } + dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event); + input_report_key(&cinergyt2->rc_input_dev, + cinergyt2->rc_input_event, 1); + cinergyt2->rc_last_code = rc_events[n].value; } } +out: schedule_delayed_work(&cinergyt2->rc_query_work, msecs_to_jiffies(RC_QUERY_INTERVAL)); @@ -771,7 +788,10 @@ static int cinergyt2_probe (struct usb_interface *intf, const struct usb_device_id *id) { struct cinergyt2 *cinergyt2; - int i, err; + int err; +#ifdef ENABLE_RC + int i; +#endif if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) { dprintk(1, "out of memory?!?\n"); @@ -827,19 +847,18 @@ static int cinergyt2_probe (struct usb_interface *intf, DVB_DEVICE_FRONTEND); #ifdef ENABLE_RC - init_input_dev(&cinergyt2->rc_input_dev); - - cinergyt2->rc_input_dev.evbit[0] = BIT(EV_KEY); - cinergyt2->rc_input_dev.keycodesize = sizeof(unsigned char); - cinergyt2->rc_input_dev.keycodemax = KEY_MAX; + cinergyt2->rc_input_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + cinergyt2->rc_input_dev.keycodesize = 0; + cinergyt2->rc_input_dev.keycodemax = 0; cinergyt2->rc_input_dev.name = DRIVER_NAME " remote control"; - for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3) - set_bit(rc_keys[i+2], cinergyt2->rc_input_dev.keybit); + for (i = 0; i < sizeof(rc_keys) / sizeof(rc_keys[0]); i += 3) + set_bit(rc_keys[i + 2], cinergyt2->rc_input_dev.keybit); input_register_device(&cinergyt2->rc_input_dev); cinergyt2->rc_input_event = KEY_MAX; + cinergyt2->rc_last_code = ~0; INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); -- GitLab From f63f5346c943008fe8f6ac66a9026f6c35e24947 Mon Sep 17 00:00:00 2001 From: thomas schorpp <t.schorpp@gmx.de> Date: Fri, 9 Sep 2005 13:03:06 -0700 Subject: [PATCH 155/563] [PATCH] dvb: av7110: Siemens DVB-C analog video input support Add support for analog video inputs (CVBS and Y/C) of the analog module for the Siemens DVB-C card. Signed-off-by: thomas schorpp <t.schorpp@gmx.de> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/ttpci/av7110_v4l.c | 74 ++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index e65fc36e2ce83..6af74f78b3e50 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -70,7 +70,7 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) return 0; } -static struct v4l2_input inputs[2] = { +static struct v4l2_input inputs[4] = { { .index = 0, .name = "DVB", @@ -87,6 +87,22 @@ static struct v4l2_input inputs[2] = { .tuner = 0, .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, .status = 0, + }, { + .index = 2, + .name = "Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + }, { + .index = 3, + .name = "Y/C", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, } }; @@ -212,24 +228,44 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh) } if (0 != av7110->current_input) { + dprintk(1, "switching to analog TV:\n"); adswitch = 1; source = SAA7146_HPS_SOURCE_PORT_B; sync = SAA7146_HPS_SYNC_PORT_B; memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2); - dprintk(1, "switching to analog TV\n"); - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source - msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source - msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source - msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { - if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) - dprintk(1, "setting band in demodulator failed.\n"); - } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD) - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9198 pin30(VIF) + switch (av7110->current_input) { + case 1: + dprintk(1, "switching SAA7113 to Analog Tuner Input.\n"); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume + + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) + dprintk(1, "setting band in demodulator failed.\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD) + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9198 pin30(VIF) + } + if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + case 2: + dprintk(1, "switching SAA7113 to Video AV CVBS Input.\n"); + if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + case 3: + dprintk(1, "switching SAA7113 to Video AV Y/C Input.\n"); + if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + default: + dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input.\n"); } } else { adswitch = 0; @@ -300,7 +336,6 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) // FIXME: standard / stereo detection is still broken msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); - msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); stereo = (s8)(stereo_det >> 8); @@ -310,7 +345,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) t->audmode = V4L2_TUNER_MODE_STEREO; } else if (stereo < -0x10) { - /* bilingual*/ + /* bilingual */ t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; t->audmode = V4L2_TUNER_MODE_LANG1; } @@ -344,7 +379,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) fm_matrix = 0x3000; // mono src = 0x0010; break; - default: /* case V4L2_TUNER_MODE_MONO: {*/ + default: /* case V4L2_TUNER_MODE_MONO: */ dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); fm_matrix = 0x3000; // mono src = 0x0030; @@ -406,7 +441,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); if (av7110->analog_tuner_flags) { - if (i->index < 0 || i->index >= 2) + if (i->index < 0 || i->index >= 4) return -EINVAL; } else { if (i->index != 0) @@ -433,10 +468,9 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) if (!av7110->analog_tuner_flags) return 0; - if (input < 0 || input >= 2) + if (input < 0 || input >= 4) return -EINVAL; - /* FIXME: switch inputs here */ av7110->current_input = input; return av7110_dvb_c_switch(fh); } -- GitLab From dc27a1696089a9a9d317fc815915e6761e22eeb5 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey <adq_dvb@lidskialf.net> Date: Fri, 9 Sep 2005 13:03:07 -0700 Subject: [PATCH 156/563] [PATCH] dvb: budget-ci: add support for TT DVB-C CI card Add support for TT DVB-C CI card. Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 97 ++++++++++- drivers/media/dvb/frontends/stv0297.c | 121 +------------- drivers/media/dvb/frontends/stv0297.h | 8 +- drivers/media/dvb/ttpci/av7110.c | 95 ++++++++++- drivers/media/dvb/ttpci/budget-ci.c | 188 +++++++++++++++++++++- 5 files changed, 387 insertions(+), 122 deletions(-) diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index a36bec3a2beaa..47e28b0ee951b 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -334,8 +334,103 @@ static struct mt312_config skystar23_samsung_tbdu18132_config = { .pll_set = skystar23_samsung_tbdu18132_pll_set, }; + +static u8 alps_tdee4_stv0297_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x00, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0xf8, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x49, + 0x62, 0x0b, + 0x53, 0x08, + 0x59, 0x08, + 0xff, 0xff, +}; + static struct stv0297_config alps_tdee4_stv0297_config = { .demod_address = 0x1c, + .inittab = alps_tdee4_stv0297_inittab, // .invert = 1, // .pll_set = alps_tdee4_stv0297_pll_set, }; @@ -369,7 +464,7 @@ int flexcop_frontend_init(struct flexcop_device *fc) info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address); } else /* try the cable dvb (stv0297) */ - if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) { + if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) { fc->dev_type = FC_CABLE; info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address); } else diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 01eb41990e8a8..8d09afd7545d8 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -35,7 +35,6 @@ struct stv0297_state { struct dvb_frontend frontend; unsigned long base_freq; - u8 pwm; }; #if 1 @@ -46,94 +45,6 @@ struct stv0297_state { #define STV0297_CLOCK_KHZ 28900 -static u8 init_tab[] = { - 0x00, 0x09, - 0x01, 0x69, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x20, 0x00, - 0x21, 0x40, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x40, - 0x25, 0x88, - 0x30, 0xff, - 0x31, 0x00, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x50, - 0x35, 0x7f, - 0x36, 0x00, - 0x37, 0x20, - 0x38, 0x00, - 0x40, 0x1c, - 0x41, 0xff, - 0x42, 0x29, - 0x43, 0x00, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0xff, - 0x4b, 0x7f, - 0x52, 0x30, - 0x55, 0xae, - 0x56, 0x47, - 0x57, 0xe1, - 0x58, 0x3a, - 0x5a, 0x1e, - 0x5b, 0x34, - 0x60, 0x00, - 0x63, 0x00, - 0x64, 0x00, - 0x65, 0x00, - 0x66, 0x00, - 0x67, 0x00, - 0x68, 0x00, - 0x69, 0x00, - 0x6a, 0x02, - 0x6b, 0x00, - 0x70, 0xff, - 0x71, 0x00, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x00, - 0x81, 0x00, - 0x82, 0x00, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x80, - 0x86, 0x24, - 0x87, 0x78, - 0x88, 0x00, - 0x89, 0x00, - 0x90, 0x01, - 0x91, 0x01, - 0xa0, 0x00, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x53, - 0xc1, 0x70, - 0xc2, 0x12, - 0xd0, 0x00, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x00, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x00, - 0x61, 0x49, - 0x62, 0x0b, - 0x53, 0x08, - 0x59, 0x08, -}; - static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data) { @@ -378,34 +289,9 @@ static int stv0297_init(struct dvb_frontend *fe) struct stv0297_state *state = fe->demodulator_priv; int i; - /* soft reset */ - stv0297_writereg_mask(state, 0x80, 1, 1); - stv0297_writereg_mask(state, 0x80, 1, 0); - - /* reset deinterleaver */ - stv0297_writereg_mask(state, 0x81, 1, 1); - stv0297_writereg_mask(state, 0x81, 1, 0); - /* load init table */ - for (i = 0; i < sizeof(init_tab); i += 2) { - stv0297_writereg(state, init_tab[i], init_tab[i + 1]); - } - - /* set a dummy symbol rate */ - stv0297_set_symbolrate(state, 6900); - - /* invert AGC1 polarity */ - stv0297_writereg_mask(state, 0x88, 0x10, 0x10); - - /* setup bit error counting */ - stv0297_writereg_mask(state, 0xA0, 0x80, 0x00); - stv0297_writereg_mask(state, 0xA0, 0x10, 0x00); - stv0297_writereg_mask(state, 0xA0, 0x08, 0x00); - stv0297_writereg_mask(state, 0xA0, 0x07, 0x04); - - /* min + max PWM */ - stv0297_writereg(state, 0x4a, 0x00); - stv0297_writereg(state, 0x4b, state->pwm); + for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2) + stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]); msleep(200); if (state->config->pll_init) @@ -738,7 +624,7 @@ static void stv0297_release(struct dvb_frontend *fe) static struct dvb_frontend_ops stv0297_ops; struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, - struct i2c_adapter *i2c, int pwm) + struct i2c_adapter *i2c) { struct stv0297_state *state = NULL; @@ -752,7 +638,6 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, state->i2c = i2c; memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); state->base_freq = 0; - state->pwm = pwm; /* check if the demod is there */ if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20) diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h index 3be535989302a..9e53f019db717 100644 --- a/drivers/media/dvb/frontends/stv0297.h +++ b/drivers/media/dvb/frontends/stv0297.h @@ -29,6 +29,12 @@ struct stv0297_config /* the demodulator's i2c address */ u8 demod_address; + /* inittab - array of pairs of values. + * First of each pair is the register, second is the value. + * List should be terminated with an 0xff, 0xff pair. + */ + u8* inittab; + /* does the "inversion" need inverted? */ u8 invert:1; @@ -38,7 +44,7 @@ struct stv0297_config }; extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, - struct i2c_adapter* i2c, int pwm); + struct i2c_adapter* i2c); extern int stv0297_enable_plli2c(struct dvb_frontend* fe); #endif // STV0297_H diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index c91cf8958b38c..48e8097d84309 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -1934,6 +1934,98 @@ static struct sp8870_config alps_tdlb7_config = { }; +static u8 nexusca_stv0297_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x00, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0x7b, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x49, + 0x62, 0x0b, + 0x53, 0x08, + 0x59, 0x08, + 0xff, 0xff, +}; static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { @@ -1982,6 +2074,7 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ static struct stv0297_config nexusca_stv0297_config = { .demod_address = 0x1C, + .inittab = nexusca_stv0297_inittab, .invert = 1, .pll_set = nexusca_stv0297_pll_set, }; @@ -2259,7 +2352,7 @@ static int frontend_init(struct av7110 *av7110) case 0x000A: // Hauppauge/TT Nexus-CA rev1.X - av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap, 0x7b); + av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap); if (av7110->fe) { /* set TDA9819 into DVB mode */ saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD) diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 88f27a5321630..2980db3ef22f8 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -40,6 +40,7 @@ #include "dvb_ca_en50221.h" #include "stv0299.h" +#include "stv0297.h" #include "tda1004x.h" #define DEBIADDR_IR 0x1234 @@ -847,6 +848,180 @@ static struct tda1004x_config philips_tdm1316l_config = { .request_firmware = philips_tdm1316l_request_firmware, }; +static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u8 tuner_buf[5]; + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, + .flags = 0, + .buf = tuner_buf, + .len = sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency + 36125000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) { + cp = 3; + band = 1; + } else if (tuner_frequency < 160000000) { + cp = 5; + band = 1; + } else if (tuner_frequency < 200000000) { + cp = 6; + band = 1; + } else if (tuner_frequency < 290000000) { + cp = 3; + band = 2; + } else if (tuner_frequency < 420000000) { + cp = 5; + band = 2; + } else if (tuner_frequency < 480000000) { + cp = 6; + band = 2; + } else if (tuner_frequency < 620000000) { + cp = 3; + band = 4; + } else if (tuner_frequency < 830000000) { + cp = 5; + band = 4; + } else if (tuner_frequency < 895000000) { + cp = 7; + band = 4; + } else + return -EINVAL; + + // assume PLL filter should always be 8MHz for the moment. + filter = 1; + + // calculate divisor + tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xc8; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + tuner_buf[4] = 0x80; + + stv0297_enable_plli2c(fe); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(50); + + stv0297_enable_plli2c(fe); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + + return 0; +} + +static u8 dvbc_philips_tdm1316l_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x20, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0x7b, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x38, + 0x62, 0x0a, + 0x53, 0x13, + 0x59, 0x08, + 0xff, 0xff, +}; + +static struct stv0297_config dvbc_philips_tdm1316l_config = { + .demod_address = 0x1c, + .inittab = dvbc_philips_tdm1316l_inittab, + .invert = 0, + .pll_set = dvbc_philips_tdm1316l_pll_set, +}; + + static void frontend_init(struct budget_ci *budget_ci) @@ -868,6 +1043,15 @@ static void frontend_init(struct budget_ci *budget_ci) } break; + case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt)) + budget_ci->tuner_pll_address = 0x61; + budget_ci->budget.dvb_frontend = + stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + break; + } + break; + case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) budget_ci->tuner_pll_address = 0x63; budget_ci->budget.dvb_frontend = @@ -877,7 +1061,7 @@ static void frontend_init(struct budget_ci *budget_ci) } break; - case 0x1012: // Hauppauge/TT Nova-T CI budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) + case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt)) budget_ci->tuner_pll_address = 0x60; budget_ci->budget.dvb_frontend = tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap); @@ -965,10 +1149,12 @@ static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), + MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), { -- GitLab From b548747d78f8840024ac3439b7149348a282e086 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey <adq_dvb@lidskialf.net> Date: Fri, 9 Sep 2005 13:03:08 -0700 Subject: [PATCH 157/563] [PATCH] dvb: budget-av: fixes for CI interface Fixes for CI interface. Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/ttpci/budget-av.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 311be50b2fce5..8c2a29007db5b 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -192,7 +192,7 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; - int timeout = 50; // 5 seconds (4.4.6 Ready) + int timeout = 500; // 5 seconds (4.4.6 Ready) if (slot != 0) return -EINVAL; @@ -217,7 +217,6 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) { printk(KERN_ERR "budget-av: cam reset failed (timeout).\n"); saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ return -ETIMEDOUT; } @@ -276,7 +275,6 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open { printk(KERN_INFO "budget-av: cam ejected\n"); saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ budget_av->slot_status = 0; } } -- GitLab From 87b2ecaebceb35c6f6199edd29ae24963d3f9c35 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey <adq_dvb@lidskialf.net> Date: Fri, 9 Sep 2005 13:03:09 -0700 Subject: [PATCH 158/563] [PATCH] dvb: budget-av: enable frontend on KNC1 Plus cards Enable frontend on KNC plus cards. Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/ttpci/budget-av.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 8c2a29007db5b..7692cd23f839c 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -743,6 +743,7 @@ static void frontend_init(struct budget_av *budget_av) case SUBID_DVBC_KNC1_PLUS: case SUBID_DVBT_KNC1_PLUS: // Enable / PowerON Frontend + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); break; } -- GitLab From ce7d3c11aee415c76bcbd5f43cace16132b48a21 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach <js@linuxtv.org> Date: Fri, 9 Sep 2005 13:03:10 -0700 Subject: [PATCH 159/563] [PATCH] dvb: av7110: disable superflous firmware handshake Disable superflous firmware handshake. Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/ttpci/av7110_hw.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 1220826696c5f..456d529cb3811 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -41,6 +41,8 @@ #include "av7110.h" #include "av7110_hw.h" +#define _NOHANDSHAKE + /**************************************************************************** * DEBI functions ****************************************************************************/ -- GitLab From 9a7b102e7f5ccb2826a81315abc89f95adaf4421 Mon Sep 17 00:00:00 2001 From: Oliver Endriss <o.endriss@gmx.de> Date: Fri, 9 Sep 2005 13:03:11 -0700 Subject: [PATCH 160/563] [PATCH] dvb: av7110: conditionally disable workaround for broken firmware Disable COM_IF_LOCK workaround for firmware > 0x261f. Signed-off-by: Oliver Endriss <o.endriss@gmx.de> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/ttpci/av7110_hw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 456d529cb3811..7442f56a72ecc 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -366,7 +366,8 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) msleep(1); } - wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); + if (FW_VERSION(av7110->arm_app) <= 0x261f) + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); #ifndef _NOHANDSHAKE start = jiffies; @@ -439,7 +440,8 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2); - wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); + if (FW_VERSION(av7110->arm_app) <= 0x261f) + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); #ifdef COM_DEBUG start = jiffies; -- GitLab From 03388ae30260475650bab24223151397afb72ec9 Mon Sep 17 00:00:00 2001 From: Oliver Endriss <o.endriss@gmx.de> Date: Fri, 9 Sep 2005 13:03:12 -0700 Subject: [PATCH 161/563] [PATCH] dvb: ttpci: av7110: RC5+ remote control support Improved remote control support for av7110-based cards: o extended rc5 protocol, firmware >= 0x2620 required o key-up timer slightly adjusted o completely moved remote control code to av7110_ir.c o support for multiple ir receivers o for now, all av7110 cards share the same ir configuration and event device Signed-off-by: Oliver Endriss <o.endriss@gmx.de> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/ttpci/av7110.c | 70 ++------------ drivers/media/dvb/ttpci/av7110.h | 11 ++- drivers/media/dvb/ttpci/av7110_ir.c | 140 +++++++++++++++++++--------- 3 files changed, 110 insertions(+), 111 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 48e8097d84309..b5d40d4243652 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -177,9 +177,6 @@ static void init_av7110_av(struct av7110 *av7110) ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); if (ret < 0) printk("dvb-ttpci:cannot set volume :%d\n",ret); - ret = av7110_setup_irc_config(av7110, 0); - if (ret < 0) - printk("dvb-ttpci:cannot setup irc config :%d\n",ret); } static void recover_arm(struct av7110 *av7110) @@ -265,60 +262,6 @@ static int arm_thread(void *data) } -/** - * Hack! we save the last av7110 ptr. This should be ok, since - * you rarely will use more then one IR control. - * - * If we want to support multiple controls we would have to do much more... - */ -int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) -{ - int ret = 0; - static struct av7110 *last; - - dprintk(4, "%p\n", av7110); - - if (!av7110) - av7110 = last; - else - last = av7110; - - if (av7110) { - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); - av7110->ir_config = ir_config; - } - return ret; -} - -static void (*irc_handler)(u32); - -void av7110_register_irc_handler(void (*func)(u32)) -{ - dprintk(4, "registering %p\n", func); - irc_handler = func; -} - -void av7110_unregister_irc_handler(void (*func)(u32)) -{ - dprintk(4, "unregistering %p\n", func); - irc_handler = NULL; -} - -static void run_handlers(unsigned long ircom) -{ - if (irc_handler != NULL) - (*irc_handler)((u32) ircom); -} - -static DECLARE_TASKLET(irtask, run_handlers, 0); - -static void IR_handle(struct av7110 *av7110, u32 ircom) -{ - dprintk(4, "ircommand = %08x\n", ircom); - irtask.data = (unsigned long) ircom; - tasklet_schedule(&irtask); -} - /**************************************************************************** * IRQ handling ****************************************************************************/ @@ -711,8 +654,9 @@ static void gpioirq(unsigned long data) return; case DATA_IRCOMMAND: - IR_handle(av7110, - swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); + if (av7110->ir_handler) + av7110->ir_handler(av7110, + swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; @@ -2783,7 +2727,7 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d goto err_av7110_exit_v4l_12; #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_ir_init(); + av7110_ir_init(av7110); #endif printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); av7110_num++; @@ -2825,6 +2769,9 @@ static int av7110_detach(struct saa7146_dev* saa) struct av7110 *av7110 = saa->ext_priv; dprintk(4, "%p\n", av7110); +#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) + av7110_ir_exit(av7110); +#endif if (budgetpatch) { /* Disable RPS1 */ saa7146_write(saa, MC1, MASK_29); @@ -2980,9 +2927,6 @@ static int __init av7110_init(void) static void __exit av7110_exit(void) { -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_ir_exit(); -#endif saa7146_unregister_extension(&av7110_extension); } diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 508b7739c6096..cce00ef293e94 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -228,7 +228,10 @@ struct av7110 { struct dvb_video_events video_events; video_size_t video_size; - u32 ir_config; + u32 ir_config; + u32 ir_command; + void (*ir_handler)(struct av7110 *av7110, u32 ircom); + struct tasklet_struct ir_tasklet; /* firmware stuff */ unsigned char *bin_fw; @@ -257,12 +260,10 @@ struct av7110 { extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid); -extern void av7110_register_irc_handler(void (*func)(u32)); -extern void av7110_unregister_irc_handler(void (*func)(u32)); extern int av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config); -extern int av7110_ir_init (void); -extern void av7110_ir_exit (void); +extern int av7110_ir_init(struct av7110 *av7110); +extern void av7110_ir_exit(struct av7110 *av7110); /* msp3400 i2c subaddresses */ #define MSP_WR_DEM 0x10 diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index 665cdb8a3f718..357a3728ec68f 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -7,16 +7,16 @@ #include <asm/bitops.h> #include "av7110.h" +#include "av7110_hw.h" -#define UP_TIMEOUT (HZ/4) +#define UP_TIMEOUT (HZ*7/25) /* enable ir debugging by or'ing debug with 16 */ -static int ir_initialized; +static int av_cnt; +static struct av7110 *av_list[4]; static struct input_dev input_dev; -static u32 ir_config; - static u16 key_map [256] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, @@ -53,8 +53,11 @@ static void av7110_emit_keyup(unsigned long data) static struct timer_list keyup_timer = { .function = av7110_emit_keyup }; -static void av7110_emit_key(u32 ircom) +static void av7110_emit_key(unsigned long parm) { + struct av7110 *av7110 = (struct av7110 *) parm; + u32 ir_config = av7110->ir_config; + u32 ircom = av7110->ir_command; u8 data; u8 addr; static u16 old_toggle = 0; @@ -62,19 +65,33 @@ static void av7110_emit_key(u32 ircom) u16 keycode; /* extract device address and data */ - if (ir_config & 0x0001) { - /* TODO RCMM: ? bits device address, 8 bits data */ + switch (ir_config & 0x0003) { + case 0: /* RC5: 5 bits device address, 6 bits data */ + data = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + break; + + case 1: /* RCMM: 8(?) bits device address, 8(?) bits data */ data = ircom & 0xff; addr = (ircom >> 8) & 0xff; - } else { - /* RC5: 5 bits device address, 6 bits data */ + break; + + case 2: /* extended RC5: 5 bits device address, 7 bits data */ data = ircom & 0x3f; addr = (ircom >> 6) & 0x1f; + /* invert 7th data bit for backward compatibility with RC5 keymaps */ + if (!(ircom & 0x1000)) + data |= 0x40; + break; + + default: + printk("invalid ir_config %x\n", ir_config); + return; } keycode = key_map[data]; - dprintk(16, "#########%08x######### addr %i data 0x%02x (keycode %i)\n", + dprintk(16, "code %08x -> addr %i data 0x%02x -> keycode %i\n", ircom, addr, data, keycode); /* check device address (if selected) */ @@ -87,10 +104,10 @@ static void av7110_emit_key(u32 ircom) return; } - if (ir_config & 0x0001) + if ((ir_config & 0x0003) == 1) new_toggle = 0; /* RCMM */ else - new_toggle = (ircom & 0x800); /* RC5 */ + new_toggle = (ircom & 0x800); /* RC5, extended RC5 */ if (timer_pending(&keyup_timer)) { del_timer(&keyup_timer); @@ -137,6 +154,8 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, { char *page; int size = 4 + 256 * sizeof(u16); + u32 ir_config; + int i; if (count < size) return -EINVAL; @@ -153,60 +172,95 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, memcpy(&ir_config, page, 4); memcpy(&key_map, page + 4, 256 * sizeof(u16)); vfree(page); - av7110_setup_irc_config(NULL, ir_config); + if (FW_VERSION(av_list[0]->arm_app) >= 0x2620 && !(ir_config & 0x0001)) + ir_config |= 0x0002; /* enable extended RC5 */ + for (i = 0; i < av_cnt; i++) + av7110_setup_irc_config(av_list[i], ir_config); input_register_keys(); return count; } -int __init av7110_ir_init(void) +int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) { - static struct proc_dir_entry *e; + int ret = 0; - if (ir_initialized) - return 0; + dprintk(4, "%p\n", av7110); + if (av7110) { + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); + av7110->ir_config = ir_config; + } + return ret; +} - init_timer(&keyup_timer); - keyup_timer.data = 0; - input_dev.name = "DVB on-card IR receiver"; +static void ir_handler(struct av7110 *av7110, u32 ircom) +{ + dprintk(4, "ircommand = %08x\n", ircom); + av7110->ir_command = ircom; + tasklet_schedule(&av7110->ir_tasklet); +} - /** - * enable keys - */ - set_bit(EV_KEY, input_dev.evbit); - set_bit(EV_REP, input_dev.evbit); - input_register_keys(); +int __init av7110_ir_init(struct av7110 *av7110) +{ + static struct proc_dir_entry *e; - input_register_device(&input_dev); - input_dev.timer.function = input_repeat_key; + if (av_cnt >= sizeof av_list/sizeof av_list[0]) + return -ENOSPC; - av7110_setup_irc_config(NULL, 0x0001); - av7110_register_irc_handler(av7110_emit_key); + av7110_setup_irc_config(av7110, 0x0001); + av_list[av_cnt++] = av7110; - e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); - if (e) { - e->write_proc = av7110_ir_write_proc; - e->size = 4 + 256 * sizeof(u16); + if (av_cnt == 1) { + init_timer(&keyup_timer); + keyup_timer.data = 0; + + input_dev.name = "DVB on-card IR receiver"; + set_bit(EV_KEY, input_dev.evbit); + set_bit(EV_REP, input_dev.evbit); + input_register_keys(); + input_register_device(&input_dev); + input_dev.timer.function = input_repeat_key; + + e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); + if (e) { + e->write_proc = av7110_ir_write_proc; + e->size = 4 + 256 * sizeof(u16); + } } - ir_initialized = 1; + tasklet_init(&av7110->ir_tasklet, av7110_emit_key, (unsigned long) av7110); + av7110->ir_handler = ir_handler; + return 0; } -void __exit av7110_ir_exit(void) +void __exit av7110_ir_exit(struct av7110 *av7110) { - if (ir_initialized == 0) + int i; + + if (av_cnt == 0) return; - del_timer_sync(&keyup_timer); - remove_proc_entry("av7110_ir", NULL); - av7110_unregister_irc_handler(av7110_emit_key); - input_unregister_device(&input_dev); - ir_initialized = 0; + + av7110->ir_handler = NULL; + tasklet_kill(&av7110->ir_tasklet); + for (i = 0; i < av_cnt; i++) + if (av_list[i] == av7110) { + av_list[i] = av_list[av_cnt-1]; + av_list[av_cnt-1] = NULL; + break; + } + + if (av_cnt == 1) { + del_timer_sync(&keyup_timer); + remove_proc_entry("av7110_ir", NULL); + input_unregister_device(&input_dev); + } + + av_cnt--; } //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>"); //MODULE_LICENSE("GPL"); - -- GitLab From 6af4ee10f0b2bec2b8c40150298a9f7c1e9e46c6 Mon Sep 17 00:00:00 2001 From: Karl Herz <karl.herz@gmx.de> Date: Fri, 9 Sep 2005 13:03:13 -0700 Subject: [PATCH 162/563] [PATCH] dvb: ttpci: add PCI ids for old Siemens/TT DVB-C card Add PCI-ids of Siemens-DVB-C card with Technotrend manufacturer id. Signed-off-by: Karl Herz <karl.herz@gmx.de> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/ttpci/av7110.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index b5d40d4243652..22b203f8ff27a 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -168,7 +168,9 @@ static void init_av7110_av(struct av7110 *av7110) if (ret < 0) printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); if (rgb_on && - (av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { + ((av7110->dev->pci->subsystem_vendor == 0x110a) || + (av7110->dev->pci->subsystem_vendor == 0x13c2)) && + (av7110->dev->pci->subsystem_device == 0x0000)) { saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16 //saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8 } @@ -2868,7 +2870,7 @@ static struct saa7146_pci_extension_data x_var = { \ .ext_priv = x_name, \ .ext = &av7110_extension } -MAKE_AV7110_INFO(tts_1_X, "Technotrend/Hauppauge WinTV DVB-S rev1.X"); +MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C"); MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X"); MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X"); MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X"); @@ -2880,16 +2882,16 @@ MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), - MAKE_EXTENSION_PCI(tts_1_X, 0x13c2, 0x0000), - MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), - MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), - MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), - MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006), - MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008), - MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), - MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e), - MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), + MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), + MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000), + MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), + MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), + MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), + MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006), + MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008), + MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), + MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e), + MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1 -- GitLab From 1ac2854cbc637de7e958cfa8d153ccf9e6668dda Mon Sep 17 00:00:00 2001 From: Philipp Matthias Hahn <pmhahn@titan.lahn.de> Date: Fri, 9 Sep 2005 13:03:13 -0700 Subject: [PATCH 163/563] [PATCH] dvb: saa7146: i2c vs. sysfs fix Integrate saa7146_i2c adapter into device model: Moves entries from /sys/device/platform to /sys/device/pci*. Signed-off-by: Philipp Hahn <pmhahn@titan.lahn.de> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/common/saa7146_i2c.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 45f86737699aa..fec6beab8c287 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -403,6 +403,7 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c if( NULL != i2c_adapter ) { BUG_ON(!i2c_adapter->class); i2c_set_adapdata(i2c_adapter,dev); + i2c_adapter->dev.parent = &dev->pci->dev; i2c_adapter->algo = &saa7146_algo; i2c_adapter->algo_data = NULL; i2c_adapter->id = I2C_HW_SAA7146; -- GitLab From 4da006c63fb4758ee2d688aa65a461337b3ed065 Mon Sep 17 00:00:00 2001 From: Marcelo Feitoza Parisi <marcelo@feitoza.com.br> Date: Fri, 9 Sep 2005 13:03:15 -0700 Subject: [PATCH 164/563] [PATCH] dvb: ttusb-budget: use time_after_eq() Use of the time_after_eq() macro, defined at linux/jiffies.h, which deal with wrapping correctly and are nicer to read. Signed-off-by: Marcelo Feitoza Parisi <marcelo@feitoza.com.br> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index c1acd4bb34992..d200ab0ad9e7f 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/time.h> #include <linux/errno.h> +#include <linux/jiffies.h> #include <asm/semaphore.h> #include "dvb_frontend.h" @@ -570,7 +571,8 @@ static void ttusb_handle_sec_data(struct ttusb_channel *channel, const u8 * data, int len); #endif -static int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid; +static int numpkt = 0, numts, numstuff, numsec, numinvalid; +static unsigned long lastj; static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack, int len) @@ -779,7 +781,7 @@ static void ttusb_iso_irq(struct urb *urb, struct pt_regs *ptregs) u8 *data; int len; numpkt++; - if ((jiffies - lastj) >= HZ) { + if (time_after_eq(jiffies, lastj + HZ)) { #if DEBUG > 2 printk ("frames/s: %d (ts: %d, stuff %d, sec: %d, invalid: %d, all: %d)\n", -- GitLab From 76fa82fb7156aa7191dfd1fdede1fc0da51d45dd Mon Sep 17 00:00:00 2001 From: Ingo Molnar <mingo@elte.hu> Date: Fri, 9 Sep 2005 13:03:21 -0700 Subject: [PATCH 165/563] [PATCH] pcmcia: reduce ds.c stack footprint This patch reduces the stack footprint of pcmcia_device_query() from 416 bytes to 36 bytes. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/pcmcia/ds.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 43da2e92d50fe..398146e3823e1 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -424,9 +424,13 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) { cistpl_manfid_t manf_id; cistpl_funcid_t func_id; - cistpl_vers_1_t vers1; + cistpl_vers_1_t *vers1; unsigned int i; + vers1 = kmalloc(sizeof(*vers1), GFP_KERNEL); + if (!vers1) + return -ENOMEM; + if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_MANFID, &manf_id)) { p_dev->manf_id = manf_id.manf; @@ -443,23 +447,30 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) /* rule of thumb: cards with no FUNCID, but with * common memory device geometry information, are * probably memory cards (from pcmcia-cs) */ - cistpl_device_geo_t devgeo; + cistpl_device_geo_t *devgeo; + + devgeo = kmalloc(sizeof(*devgeo), GFP_KERNEL); + if (!devgeo) { + kfree(vers1); + return -ENOMEM; + } if (!pccard_read_tuple(p_dev->socket, p_dev->func, - CISTPL_DEVICE_GEO, &devgeo)) { + CISTPL_DEVICE_GEO, devgeo)) { ds_dbg(0, "mem device geometry probably means " "FUNCID_MEMORY\n"); p_dev->func_id = CISTPL_FUNCID_MEMORY; p_dev->has_func_id = 1; } + kfree(devgeo); } if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_VERS_1, - &vers1)) { - for (i=0; i < vers1.ns; i++) { + vers1)) { + for (i=0; i < vers1->ns; i++) { char *tmp; unsigned int length; - tmp = vers1.str + vers1.ofs[i]; + tmp = vers1->str + vers1->ofs[i]; length = strlen(tmp) + 1; if ((length < 3) || (length > 255)) @@ -475,6 +486,7 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) } } + kfree(vers1); return 0; } -- GitLab From b3743fa4442fc172e950ff0eaf6aa96e7d5ce9be Mon Sep 17 00:00:00 2001 From: Dominik Brodowski <linux@dominikbrodowski.net> Date: Fri, 9 Sep 2005 13:03:23 -0700 Subject: [PATCH 166/563] [PATCH] yenta: share code with PCI core Share code between setup-bus.c and yenta_socket.c: use the write-out code of resources to the bridge also in yenta_socket.c, as it provides useful debug output. In addition, it fixes the bug that the CPU-centric resource view might need to be transferred to the PCI-centric view: setup-bus.c does that, while yenta-socket.c did not. Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/pci/setup-bus.c | 4 ++-- drivers/pcmcia/yenta_socket.c | 41 +++++++++++++++-------------------- include/linux/pci.h | 1 + 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 6b0e6464eb391..657be948baf71 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -77,8 +77,7 @@ pbus_assign_resources_sorted(struct pci_bus *bus) } } -static void __devinit -pci_setup_cardbus(struct pci_bus *bus) +void pci_setup_cardbus(struct pci_bus *bus) { struct pci_dev *bridge = bus->self; struct pci_bus_region region; @@ -130,6 +129,7 @@ pci_setup_cardbus(struct pci_bus *bus) region.end); } } +EXPORT_SYMBOL(pci_setup_cardbus); /* Initialize bridges with base/limit values we have collected. PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 0347a29f297be..271a52b7c2e6b 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -667,7 +667,7 @@ static int yenta_search_res(struct yenta_socket *socket, struct resource *res, return 0; } -static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) +static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) { struct resource *root, *res; struct pci_bus_region region; @@ -676,7 +676,7 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; /* Already allocated? */ if (res->parent) - return; + return 0; /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */ mask = ~0xfff; @@ -692,7 +692,7 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ pcibios_bus_to_resource(socket->dev, res, ®ion); root = pci_find_parent_resource(socket->dev, res); if (root && (request_resource(root, res) == 0)) - return; + return 0; printk(KERN_INFO "yenta %s: Preassigned resource %d busy or not available, reconfiguring...\n", pci_name(socket->dev), nr); } @@ -700,35 +700,27 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ if (type & IORESOURCE_IO) { if ((yenta_search_res(socket, res, BRIDGE_IO_MAX)) || (yenta_search_res(socket, res, BRIDGE_IO_ACC)) || - (yenta_search_res(socket, res, BRIDGE_IO_MIN))) { - config_writel(socket, addr_start, res->start); - config_writel(socket, addr_end, res->end); - return; - } + (yenta_search_res(socket, res, BRIDGE_IO_MIN))) + return 1; } else { if (type & IORESOURCE_PREFETCH) { if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || - (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { - config_writel(socket, addr_start, res->start); - config_writel(socket, addr_end, res->end); - return; - } + (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) + return 1; /* Approximating prefetchable by non-prefetchable */ res->flags = IORESOURCE_MEM; } if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || - (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { - config_writel(socket, addr_start, res->start); - config_writel(socket, addr_end, res->end); - return; - } + (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) + return 1; } printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", pci_name(socket->dev), type); res->start = res->end = res->flags = 0; + return 0; } /* @@ -736,14 +728,17 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ */ static void yenta_allocate_resources(struct yenta_socket *socket) { - yenta_allocate_res(socket, 0, IORESOURCE_IO, + int program = 0; + program += yenta_allocate_res(socket, 0, IORESOURCE_IO, PCI_CB_IO_BASE_0, PCI_CB_IO_LIMIT_0); - yenta_allocate_res(socket, 1, IORESOURCE_IO, + program += yenta_allocate_res(socket, 1, IORESOURCE_IO, PCI_CB_IO_BASE_1, PCI_CB_IO_LIMIT_1); - yenta_allocate_res(socket, 2, IORESOURCE_MEM|IORESOURCE_PREFETCH, + program += yenta_allocate_res(socket, 2, IORESOURCE_MEM|IORESOURCE_PREFETCH, PCI_CB_MEMORY_BASE_0, PCI_CB_MEMORY_LIMIT_0); - yenta_allocate_res(socket, 3, IORESOURCE_MEM, + program += yenta_allocate_res(socket, 3, IORESOURCE_MEM, PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1); + if (program) + pci_setup_cardbus(socket->dev->subordinate); } @@ -758,7 +753,7 @@ static void yenta_free_resources(struct yenta_socket *socket) res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i; if (res->start != 0 && res->end != 0) release_resource(res); - res->start = res->end = 0; + res->start = res->end = res->flags = 0; } } diff --git a/include/linux/pci.h b/include/linux/pci.h index 6caaba0af4697..c62e892702370 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -326,6 +326,7 @@ extern struct pci_dev *pci_dev_get(struct pci_dev *dev); extern void pci_dev_put(struct pci_dev *dev); extern void pci_remove_bus(struct pci_bus *b); extern void pci_remove_bus_device(struct pci_dev *dev); +void pci_setup_cardbus(struct pci_bus *bus); /* Generic PCI functions exported to card drivers */ -- GitLab From bf4de6f2db79f3c396bd884f546cd2ea91a686f2 Mon Sep 17 00:00:00 2001 From: Daniel Ritz <daniel.ritz@gmx.ch> Date: Fri, 9 Sep 2005 13:03:23 -0700 Subject: [PATCH 167/563] [PATCH] pcmcia/cs: fix possible missed wakeup - thread_done should only be completed when the wait_queue is installed. - all wake up conditions should be checked before schedule() this fixes a hang of rmmod in the sequence modprobe yenta_socket; rmmod yenta_socket as reported by Andreas Steinmetz. w/o this rmmod yenta_socket can hang on wait_for_completion() in pcmcia_unregister_socket() Signed-off-by: Daniel Ritz <daniel.ritz@gmx.ch> Cc: Dominik Brodowski <linux@brodo.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/pcmcia/cs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index e39178fc59d08..fabd3529cebcb 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -654,9 +654,10 @@ static int pccardd(void *__skt) skt->thread = NULL; complete_and_exit(&skt->thread_done, 0); } - complete(&skt->thread_done); add_wait_queue(&skt->thread_wait, &wait); + complete(&skt->thread_done); + for (;;) { unsigned long flags; unsigned int events; @@ -682,11 +683,11 @@ static int pccardd(void *__skt) continue; } - schedule(); - try_to_freeze(); - if (!skt->thread) break; + + schedule(); + try_to_freeze(); } remove_wait_queue(&skt->thread_wait, &wait); -- GitLab From c181e0e00ff778623c7fda055fd404a06d2c7845 Mon Sep 17 00:00:00 2001 From: Daniel Ritz <daniel.ritz@gmx.ch> Date: Fri, 9 Sep 2005 13:03:25 -0700 Subject: [PATCH 168/563] [PATCH] fix pcmcia_request_irq() for multifunction card multifunction cards need to have the same irq assigned to both functions. the code tries that but fails because ret is still set to CS_IN_USE which results in the function having the CB irq assigned. yenta_set_socket then just changes the irq routing to use the PCI interrupt but the first functions irq handler is registered on an ISA interrupt. boom. Signed-off-by: Daniel Ritz <daniel.ritz@gmx.ch> Cc: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/pcmcia/pcmcia_resource.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 599b116d97472..c0f4eb49177bf 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -832,7 +832,8 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) } } #endif - if (ret) { + /* only assign PCI irq if no IRQ already assigned */ + if (ret && !s->irq.AssignedIRQ) { if (!s->pci_irq) return ret; irq = s->pci_irq; -- GitLab From c8751e4c0bd32ecb76434240a56a087fa223280c Mon Sep 17 00:00:00 2001 From: Daniel Ritz <daniel.ritz@gmx.ch> Date: Fri, 9 Sep 2005 13:03:25 -0700 Subject: [PATCH 169/563] [PATCH] pcmcia/yenta: avoid PCI write posting problem extend cb_writel(), exca_writeb(), exca_writel() to do a read[lb]() after the write[lb]() to avoid possible problem with PCI write posting. Seems to fix Bug #5061. Signed-off-by: Daniel Ritz <daniel.ritz@gmx.ch> Cc: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/pcmcia/yenta_socket.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 271a52b7c2e6b..f0997c36c9b71 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -72,6 +72,7 @@ static inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val) { debug("%p %04x %08x\n", socket, reg, val); writel(val, socket->base + reg); + readl(socket->base + reg); /* avoid problems with PCI write posting */ } static inline u8 config_readb(struct yenta_socket *socket, unsigned offset) @@ -136,6 +137,7 @@ static inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val { debug("%p %04x %02x\n", socket, reg, val); writeb(val, socket->base + 0x800 + reg); + readb(socket->base + 0x800 + reg); /* PCI write posting... */ } static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) @@ -143,6 +145,10 @@ static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) debug("%p %04x %04x\n", socket, reg, val); writeb(val, socket->base + 0x800 + reg); writeb(val >> 8, socket->base + 0x800 + reg + 1); + + /* PCI write posting... */ + readb(socket->base + 0x800 + reg); + readb(socket->base + 0x800 + reg + 1); } /* -- GitLab From 76d82ec526b0549cedf332d80929c8c225b653fa Mon Sep 17 00:00:00 2001 From: Dominik Brodowski <linux@dominikbrodowski.net> Date: Fri, 9 Sep 2005 13:03:26 -0700 Subject: [PATCH 170/563] [PATCH] pcmcia: remove unused client_t client_t and CLIENT_MAGIC are unused, so remove them Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/pcmcia/cs_internal.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 6bbfbd0e02a5d..4d5ffdcfeca37 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -17,9 +17,6 @@ #include <linux/config.h> -#define CLIENT_MAGIC 0x51E6 -typedef struct client_t client_t; - /* Flags in client state */ #define CLIENT_CONFIG_LOCKED 0x0001 #define CLIENT_IRQ_REQ 0x0002 -- GitLab From 71ed90d89eff51a1137cbef727f11b8f7d5b20f1 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski <linux@dominikbrodowski.net> Date: Fri, 9 Sep 2005 13:03:27 -0700 Subject: [PATCH 171/563] [PATCH] pcmcia: remove unused Vpp1, Vpp2 and Vcc config_t->Vpp1, Vpp2 and Vcc are never read, so remove them. Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/pcmcia/cs_internal.h | 1 - drivers/pcmcia/pcmcia_resource.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 4d5ffdcfeca37..55867bc7f1996 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -42,7 +42,6 @@ typedef struct region_t { typedef struct config_t { u_int state; u_int Attributes; - u_int Vcc, Vpp1, Vpp2; u_int IntType; u_int ConfigBase; u_char Status, Pin, Copy, Option, ExtStatus; diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index c0f4eb49177bf..deb6d00bc2ff5 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -447,7 +447,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { if (mod->Vpp1 != mod->Vpp2) return CS_BAD_VPP; - c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1; + s->socket.Vpp = mod->Vpp1; if (s->ops->set_socket(s, &s->socket)) return CS_BAD_VPP; } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || @@ -623,8 +623,6 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, if (s->ops->set_socket(s, &s->socket)) return CS_BAD_VPP; - c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1; - /* Pick memory or I/O card, DMA mode, interrupt */ c->IntType = req->IntType; c->Attributes = req->Attributes; -- GitLab From f74e48a51c38f54fa26eb86a7a42f592156eccc2 Mon Sep 17 00:00:00 2001 From: David Brownell <dbrownell@users.sourceforge.net> Date: Fri, 9 Sep 2005 13:03:28 -0700 Subject: [PATCH 172/563] [PATCH] pcmcia: OMAP CF controller This adds a socket driver for the OMAP CF controller; it's currently in use on OSK boards. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/pcmcia/Kconfig | 7 + drivers/pcmcia/Makefile | 1 + drivers/pcmcia/omap_cf.c | 373 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 381 insertions(+) create mode 100644 drivers/pcmcia/omap_cf.c diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 6485f75d2fb3b..ddc741e6ecbff 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -221,6 +221,13 @@ config PCMCIA_VRC4173 tristate "NEC VRC4173 CARDU support" depends on CPU_VR41XX && PCI && PCMCIA +config OMAP_CF + tristate "OMAP CompactFlash Controller" + depends on PCMCIA && ARCH_OMAP16XX + help + Say Y here to support the CompactFlash controller on OMAP. + Note that this doesn't support "True IDE" mode. + config PCCARD_NONSTATIC tristate diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index ef694c74dfb7e..a41fbb38fdcbe 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_M32R_CFC) += m32r_cfc.o obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o +obj-$(CONFIG_OMAP_CF) += omap_cf.o sa11xx_core-y += soc_common.o sa11xx_base.o pxa2xx_core-y += soc_common.o pxa2xx_base.o diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c new file mode 100644 index 0000000000000..08d1c92882647 --- /dev/null +++ b/drivers/pcmcia/omap_cf.c @@ -0,0 +1,373 @@ +/* + * omap_cf.c -- OMAP 16xx CompactFlash controller driver + * + * Copyright (c) 2005 David Brownell + * + * 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. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include <pcmcia/ss.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/mach-types.h> +#include <asm/sizes.h> + +#include <asm/arch/mux.h> +#include <asm/arch/tc.h> + + +/* NOTE: don't expect this to support many I/O cards. The 16xx chips have + * hard-wired timings to support Compact Flash memory cards; they won't work + * with various other devices (like WLAN adapters) without some external + * logic to help out. + * + * NOTE: CF controller docs disagree with address space docs as to where + * CF_BASE really lives; this is a doc erratum. + */ +#define CF_BASE 0xfffe2800 + +/* status; read after IRQ */ +#define CF_STATUS_REG __REG16(CF_BASE + 0x00) +# define CF_STATUS_BAD_READ (1 << 2) +# define CF_STATUS_BAD_WRITE (1 << 1) +# define CF_STATUS_CARD_DETECT (1 << 0) + +/* which chipselect (CS0..CS3) is used for CF (active low) */ +#define CF_CFG_REG __REG16(CF_BASE + 0x02) + +/* card reset */ +#define CF_CONTROL_REG __REG16(CF_BASE + 0x04) +# define CF_CONTROL_RESET (1 << 0) + +#define omap_cf_present() (!(CF_STATUS_REG & CF_STATUS_CARD_DETECT)) + +/*--------------------------------------------------------------------------*/ + +static const char driver_name[] = "omap_cf"; + +struct omap_cf_socket { + struct pcmcia_socket socket; + + struct timer_list timer; + unsigned present:1; + unsigned active:1; + + struct platform_device *pdev; + unsigned long phys_cf; + u_int irq; +}; + +#define POLL_INTERVAL (2 * HZ) + +#define SZ_2K (2 * SZ_1K) + +/*--------------------------------------------------------------------------*/ + +static int omap_cf_ss_init(struct pcmcia_socket *s) +{ + return 0; +} + +/* the timer is primarily to kick this socket's pccardd */ +static void omap_cf_timer(unsigned long _cf) +{ + struct omap_cf_socket *cf = (void *) _cf; + unsigned present = omap_cf_present(); + + if (present != cf->present) { + cf->present = present; + pr_debug("%s: card %s\n", driver_name, + present ? "present" : "gone"); + pcmcia_parse_events(&cf->socket, SS_DETECT); + } + + if (cf->active) + mod_timer(&cf->timer, jiffies + POLL_INTERVAL); +} + +/* This irq handler prevents "irqNNN: nobody cared" messages as drivers + * claim the card's IRQ. It may also detect some card insertions, but + * not removals; it can't always eliminate timer irqs. + */ +static irqreturn_t omap_cf_irq(int irq, void *_cf, struct pt_regs *r) +{ + omap_cf_timer((unsigned long)_cf); + return IRQ_HANDLED; +} + +static int omap_cf_get_status(struct pcmcia_socket *s, u_int *sp) +{ + if (!sp) + return -EINVAL; + + /* FIXME power management should probably be board-specific: + * - 3VCARD vs XVCARD (OSK only handles 3VCARD) + * - POWERON (switched on/off by set_socket) + */ + if (omap_cf_present()) { + struct omap_cf_socket *cf; + + *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD; + cf = container_of(s, struct omap_cf_socket, socket); + s->irq.AssignedIRQ = cf->irq; + } else + *sp = 0; + return 0; +} + +static int +omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s) +{ + u16 control; + + /* FIXME some non-OSK boards will support power switching */ + switch (s->Vcc) { + case 0: + case 33: + break; + default: + return -EINVAL; + } + + control = CF_CONTROL_REG; + if (s->flags & SS_RESET) + CF_CONTROL_REG = CF_CONTROL_RESET; + else + CF_CONTROL_REG = 0; + + pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n", + driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask); + + return 0; +} + +static int omap_cf_ss_suspend(struct pcmcia_socket *s) +{ + pr_debug("%s: %s\n", driver_name, __FUNCTION__); + return omap_cf_set_socket(s, &dead_socket); +} + +/* regions are 2K each: mem, attrib, io (and reserved-for-ide) */ + +static int +omap_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) +{ + struct omap_cf_socket *cf; + + cf = container_of(s, struct omap_cf_socket, socket); + io->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT; + io->start = cf->phys_cf + SZ_4K; + io->stop = io->start + SZ_2K - 1; + return 0; +} + +static int +omap_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map) +{ + struct omap_cf_socket *cf; + + if (map->card_start) + return -EINVAL; + cf = container_of(s, struct omap_cf_socket, socket); + map->static_start = cf->phys_cf; + map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT; + if (map->flags & MAP_ATTRIB) + map->static_start += SZ_2K; + return 0; +} + +static struct pccard_operations omap_cf_ops = { + .init = omap_cf_ss_init, + .suspend = omap_cf_ss_suspend, + .get_status = omap_cf_get_status, + .set_socket = omap_cf_set_socket, + .set_io_map = omap_cf_set_io_map, + .set_mem_map = omap_cf_set_mem_map, +}; + +/*--------------------------------------------------------------------------*/ + +/* + * NOTE: right now the only board-specific platform_data is + * "what chipselect is used". Boards could want more. + */ + +static int __init omap_cf_probe(struct device *dev) +{ + unsigned seg; + struct omap_cf_socket *cf; + struct platform_device *pdev = to_platform_device(dev); + int irq; + int status; + + seg = (int) dev->platform_data; + if (seg == 0 || seg > 3) + return -ENODEV; + + /* either CFLASH.IREQ (INT_1610_CF) or some GPIO */ + irq = platform_get_irq(pdev, 0); + if (!irq) + return -EINVAL; + + cf = kcalloc(1, sizeof *cf, GFP_KERNEL); + if (!cf) + return -ENOMEM; + init_timer(&cf->timer); + cf->timer.function = omap_cf_timer; + cf->timer.data = (unsigned long) cf; + + cf->pdev = pdev; + dev_set_drvdata(dev, cf); + + /* this primarily just shuts up irq handling noise */ + status = request_irq(irq, omap_cf_irq, SA_SHIRQ, + driver_name, cf); + if (status < 0) + goto fail0; + cf->irq = irq; + cf->socket.pci_irq = irq; + + switch (seg) { + /* NOTE: CS0 could be configured too ... */ + case 1: + cf->phys_cf = OMAP_CS1_PHYS; + break; + case 2: + cf->phys_cf = OMAP_CS2_PHYS; + break; + case 3: + cf->phys_cf = omap_cs3_phys(); + break; + default: + goto fail1; + } + + /* pcmcia layer only remaps "real" memory */ + cf->socket.io_offset = (unsigned long) + ioremap(cf->phys_cf + SZ_4K, SZ_2K); + if (!cf->socket.io_offset) + goto fail1; + + if (!request_mem_region(cf->phys_cf, SZ_8K, driver_name)) + goto fail1; + + /* NOTE: CF conflicts with MMC1 */ + omap_cfg_reg(W11_1610_CF_CD1); + omap_cfg_reg(P11_1610_CF_CD2); + omap_cfg_reg(R11_1610_CF_IOIS16); + omap_cfg_reg(V10_1610_CF_IREQ); + omap_cfg_reg(W10_1610_CF_RESET); + + CF_CFG_REG = ~(1 << seg); + + pr_info("%s: cs%d on irq %d\n", driver_name, seg, irq); + + /* NOTE: better EMIFS setup might support more cards; but the + * TRM only shows how to affect regular flash signals, not their + * CF/PCMCIA variants... + */ + pr_debug("%s: cs%d, previous ccs %08x acs %08x\n", driver_name, + seg, EMIFS_CCS(seg), EMIFS_ACS(seg)); + EMIFS_CCS(seg) = 0x0004a1b3; /* synch mode 4 etc */ + EMIFS_ACS(seg) = 0x00000000; /* OE hold/setup */ + + /* CF uses armxor_ck, which is "always" available */ + + pr_debug("%s: sts %04x cfg %04x control %04x %s\n", driver_name, + CF_STATUS_REG, CF_CFG_REG, CF_CONTROL_REG, + omap_cf_present() ? "present" : "(not present)"); + + cf->socket.owner = THIS_MODULE; + cf->socket.dev.dev = dev; + cf->socket.ops = &omap_cf_ops; + cf->socket.resource_ops = &pccard_static_ops; + cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP + | SS_CAP_MEM_ALIGN; + cf->socket.map_size = SZ_2K; + + status = pcmcia_register_socket(&cf->socket); + if (status < 0) + goto fail2; + + cf->active = 1; + mod_timer(&cf->timer, jiffies + POLL_INTERVAL); + return 0; + +fail2: + iounmap((void __iomem *) cf->socket.io_offset); + release_mem_region(cf->phys_cf, SZ_8K); +fail1: + free_irq(irq, cf); +fail0: + kfree(cf); + return status; +} + +static int __devexit omap_cf_remove(struct device *dev) +{ + struct omap_cf_socket *cf = dev_get_drvdata(dev); + + cf->active = 0; + pcmcia_unregister_socket(&cf->socket); + del_timer_sync(&cf->timer); + iounmap((void __iomem *) cf->socket.io_offset); + release_mem_region(cf->phys_cf, SZ_8K); + free_irq(cf->irq, cf); + kfree(cf); + return 0; +} + +static int omap_cf_suspend(struct device *dev, pm_message_t mesg, u32 level) +{ + if (level != SUSPEND_SAVE_STATE) + return 0; + return pcmcia_socket_dev_suspend(dev, mesg); +} + +static int omap_cf_resume(struct device *dev, u32 level) +{ + if (level != RESUME_RESTORE_STATE) + return 0; + return pcmcia_socket_dev_resume(dev); +} + +static struct device_driver omap_cf_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, + .probe = omap_cf_probe, + .remove = __devexit_p(omap_cf_remove), + .suspend = omap_cf_suspend, + .resume = omap_cf_resume, +}; + +static int __init omap_cf_init(void) +{ + if (cpu_is_omap16xx()) + driver_register(&omap_cf_driver); + return 0; +} + +static void __exit omap_cf_exit(void) +{ + if (cpu_is_omap16xx()) + driver_unregister(&omap_cf_driver); +} + +module_init(omap_cf_init); +module_exit(omap_cf_exit); + +MODULE_DESCRIPTION("OMAP CF Driver"); +MODULE_LICENSE("GPL"); -- GitLab From d3feb1844ad33911ab1fe9df1ead66082b3bce9b Mon Sep 17 00:00:00 2001 From: Dominik Brodowski <linux@dominikbrodowski.net> Date: Fri, 9 Sep 2005 13:03:28 -0700 Subject: [PATCH 173/563] [PATCH] pcmcia: more IDs for ide_cs (Partly From: David Brownell <dbrownell@users.sourceforge.net> ) Make ID-CS recognize the CF card manufacturer records for Samsung, Lexar and STI. Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/ide/legacy/ide-cs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index f1d1ec4e96771..dc0841b2721c6 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -454,9 +454,12 @@ int ide_event(event_t event, int priority, static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_FUNC_ID(4), PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), + PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), + PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), + PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), + PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */ PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0), PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74), PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9), @@ -481,6 +484,7 @@ static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003), PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), + PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e), PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6), PCMCIA_DEVICE_NULL, }; -- GitLab From bd65a68574b787304a0cd90f22cfd44540ce3695 Mon Sep 17 00:00:00 2001 From: Brice Goglin <Brice.Goglin@ens-lyon.org> Date: Fri, 9 Sep 2005 13:03:29 -0700 Subject: [PATCH 174/563] [PATCH] pcmcia: add pcmcia to IRQ information Add a devname parameter to the pcmcia_device structure, fills it with "pcmcia<bus_id>" in pcmcia_device_add, and passes it to request_irq in pcmcia_request_irq. Signed-off-by: Brice Goglin <Brice.Goglin@ens-lyon.org> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/pcmcia/ds.c | 10 +++++++++- drivers/pcmcia/pcmcia_resource.c | 4 ++-- include/pcmcia/ds.h | 2 ++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 398146e3823e1..080608c7381a7 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -354,6 +354,7 @@ static void pcmcia_release_dev(struct device *dev) struct pcmcia_device *p_dev = to_pcmcia_dev(dev); ds_dbg(1, "releasing dev %p\n", p_dev); pcmcia_put_socket(p_dev->socket); + kfree(p_dev->devname); kfree(p_dev); } @@ -504,6 +505,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f { struct pcmcia_device *p_dev; unsigned long flags; + int bus_id_len; s = pcmcia_get_socket(s); if (!s) @@ -527,7 +529,12 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f p_dev->dev.bus = &pcmcia_bus_type; p_dev->dev.parent = s->dev.dev; p_dev->dev.release = pcmcia_release_dev; - sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); + bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); + + p_dev->devname = kmalloc(6 + bus_id_len + 1, GFP_KERNEL); + if (!p_dev->devname) + goto err_free; + sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id); /* compat */ p_dev->state = CLIENT_UNBOUND; @@ -552,6 +559,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f return p_dev; err_free: + kfree(p_dev->devname); kfree(p_dev); s->device_count--; err_put: diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index deb6d00bc2ff5..89022ad5b5207 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -820,7 +820,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || (s->functions > 1) || (irq == s->pci_irq)) ? SA_SHIRQ : 0, - p_dev->dev.bus_id, + p_dev->devname, (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data); if (!ret) { if (!(req->Attributes & IRQ_HANDLE_PRESENT)) @@ -842,7 +842,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || (s->functions > 1) || (irq == s->pci_irq)) ? SA_SHIRQ : 0, - p_dev->dev.bus_id, req->Instance)) + p_dev->devname, req->Instance)) return CS_IN_USE; } diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index b707a603351b2..cb8b6e6ce66c9 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -151,6 +151,8 @@ struct pcmcia_device { uniquely define a pcmcia_device */ struct pcmcia_socket *socket; + char *devname; + u8 device_no; /* the hardware "function" device; certain subdevices can -- GitLab From e498be7dafd72fd68848c1eef1575aa7c5d658df Mon Sep 17 00:00:00 2001 From: Christoph Lameter <clameter@engr.sgi.com> Date: Fri, 9 Sep 2005 13:03:32 -0700 Subject: [PATCH 175/563] [PATCH] Numa-aware slab allocator V5 The NUMA API change that introduced kmalloc_node was accepted for 2.6.12-rc3. Now it is possible to do slab allocations on a node to localize memory structures. This API was used by the pageset localization patch and the block layer localization patch now in mm. The existing kmalloc_node is slow since it simply searches through all pages of the slab to find a page that is on the node requested. The two patches do a one time allocation of slab structures at initialization and therefore the speed of kmalloc node does not matter. This patch allows kmalloc_node to be as fast as kmalloc by introducing node specific page lists for partial, free and full slabs. Slab allocation improves in a NUMA system so that we are seeing a performance gain in AIM7 of about 5% with this patch alone. More NUMA localizations are possible if kmalloc_node operates in an fast way like kmalloc. Test run on a 32p systems with 32G Ram. w/o patch Tasks jobs/min jti jobs/min/task real cpu 1 485.36 100 485.3640 11.99 1.91 Sat Apr 30 14:01:51 2005 100 26582.63 88 265.8263 21.89 144.96 Sat Apr 30 14:02:14 2005 200 29866.83 81 149.3342 38.97 286.08 Sat Apr 30 14:02:53 2005 300 33127.16 78 110.4239 52.71 426.54 Sat Apr 30 14:03:46 2005 400 34889.47 80 87.2237 66.72 568.90 Sat Apr 30 14:04:53 2005 500 35654.34 76 71.3087 81.62 714.55 Sat Apr 30 14:06:15 2005 600 36460.83 75 60.7681 95.77 853.42 Sat Apr 30 14:07:51 2005 700 35957.00 75 51.3671 113.30 990.67 Sat Apr 30 14:09:45 2005 800 33380.65 73 41.7258 139.48 1140.86 Sat Apr 30 14:12:05 2005 900 35095.01 76 38.9945 149.25 1281.30 Sat Apr 30 14:14:35 2005 1000 36094.37 74 36.0944 161.24 1419.66 Sat Apr 30 14:17:17 2005 w/patch Tasks jobs/min jti jobs/min/task real cpu 1 484.27 100 484.2736 12.02 1.93 Sat Apr 30 15:59:45 2005 100 28262.03 90 282.6203 20.59 143.57 Sat Apr 30 16:00:06 2005 200 32246.45 82 161.2322 36.10 282.89 Sat Apr 30 16:00:42 2005 300 37945.80 83 126.4860 46.01 418.75 Sat Apr 30 16:01:28 2005 400 40000.69 81 100.0017 58.20 561.48 Sat Apr 30 16:02:27 2005 500 40976.10 78 81.9522 71.02 696.95 Sat Apr 30 16:03:38 2005 600 41121.54 78 68.5359 84.92 834.86 Sat Apr 30 16:05:04 2005 700 44052.77 78 62.9325 92.48 971.53 Sat Apr 30 16:06:37 2005 800 41066.89 79 51.3336 113.38 1111.15 Sat Apr 30 16:08:31 2005 900 38918.77 79 43.2431 134.59 1252.57 Sat Apr 30 16:10:46 2005 1000 41842.21 76 41.8422 139.09 1392.33 Sat Apr 30 16:13:05 2005 These are measurement taken directly after boot and show a greater improvement than 5%. However, the performance improvements become less over time if the AIM7 runs are repeated and settle down at around 5%. Links to earlier discussions: http://marc.theaimsgroup.com/?t=111094594500003&r=1&w=2 http://marc.theaimsgroup.com/?t=111603406600002&r=1&w=2 Changelog V4-V5: - alloc_arraycache and alloc_aliencache take node parameter instead of cpu - fix initialization so that nodes without cpus are properly handled. - simplify code in kmem_cache_init - patch against Andrews temp mm3 release - Add Shai to credits - fallback to __cache_alloc from __cache_alloc_node if the node's cache is not available yet. Changelog V3-V4: - Patch against 2.6.12-rc5-mm1 - Cleanup patch integrated - More and better use of for_each_node and for_each_cpu - GCC 2.95 fix (do not use [] use [0]) - Correct determination of INDEX_AC - Remove hack to cause an error on platforms that have no CONFIG_NUMA but nodes. - Remove list3_data and list3_data_ptr macros for better readability Changelog V2-V3: - Made to patch against 2.6.12-rc4-mm1 - Revised bootstrap mechanism so that larger size kmem_list3 structs can be supported. Do a generic solution so that the right slab can be found for the internal structs. - use for_each_online_node Changelog V1-V2: - Batching for freeing of wrong-node objects (alien caches) - Locking changes and NUMA #ifdefs as requested by Manfred Signed-off-by: Alok N Kataria <alokk@calsoftinc.com> Signed-off-by: Shobhit Dayal <shobhit@calsoftinc.com> Signed-off-by: Shai Fultheim <Shai@Scalex86.org> Signed-off-by: Christoph Lameter <clameter@sgi.com> Cc: Manfred Spraul <manfred@colorfullife.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- mm/slab.c | 1132 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 812 insertions(+), 320 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index d7c4443991fe8..a041c5378dfa5 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -75,6 +75,15 @@ * * At present, each engine can be growing a cache. This should be blocked. * + * 15 March 2005. NUMA slab allocator. + * Shai Fultheim <shai@scalex86.org>. + * Shobhit Dayal <shobhit@calsoftinc.com> + * Alok N Kataria <alokk@calsoftinc.com> + * Christoph Lameter <christoph@lameter.com> + * + * Modified the slab allocator to be node aware on NUMA systems. + * Each node has its own list of partial, free and full slabs. + * All object allocations for a node occur from node specific slab lists. */ #include <linux/config.h> @@ -93,6 +102,7 @@ #include <linux/module.h> #include <linux/rcupdate.h> #include <linux/string.h> +#include <linux/nodemask.h> #include <asm/uaccess.h> #include <asm/cacheflush.h> @@ -212,6 +222,7 @@ struct slab { void *s_mem; /* including colour offset */ unsigned int inuse; /* num of objs active in slab */ kmem_bufctl_t free; + unsigned short nodeid; }; /* @@ -239,7 +250,6 @@ struct slab_rcu { /* * struct array_cache * - * Per cpu structures * Purpose: * - LIFO ordering, to hand out cache-warm objects from _alloc * - reduce the number of linked list operations @@ -254,6 +264,13 @@ struct array_cache { unsigned int limit; unsigned int batchcount; unsigned int touched; + spinlock_t lock; + void *entry[0]; /* + * Must have this definition in here for the proper + * alignment of array_cache. Also simplifies accessing + * the entries. + * [0] is for gcc 2.95. It should really be []. + */ }; /* bootstrap: The caches do not work without cpuarrays anymore, @@ -266,34 +283,83 @@ struct arraycache_init { }; /* - * The slab lists of all objects. - * Hopefully reduce the internal fragmentation - * NUMA: The spinlock could be moved from the kmem_cache_t - * into this structure, too. Figure out what causes - * fewer cross-node spinlock operations. + * The slab lists for all objects. */ struct kmem_list3 { struct list_head slabs_partial; /* partial list first, better asm code */ struct list_head slabs_full; struct list_head slabs_free; unsigned long free_objects; - int free_touched; unsigned long next_reap; - struct array_cache *shared; + int free_touched; + unsigned int free_limit; + spinlock_t list_lock; + struct array_cache *shared; /* shared per node */ + struct array_cache **alien; /* on other nodes */ }; -#define LIST3_INIT(parent) \ - { \ - .slabs_full = LIST_HEAD_INIT(parent.slabs_full), \ - .slabs_partial = LIST_HEAD_INIT(parent.slabs_partial), \ - .slabs_free = LIST_HEAD_INIT(parent.slabs_free) \ +/* + * Need this for bootstrapping a per node allocator. + */ +#define NUM_INIT_LISTS (2 * MAX_NUMNODES + 1) +struct kmem_list3 __initdata initkmem_list3[NUM_INIT_LISTS]; +#define CACHE_CACHE 0 +#define SIZE_AC 1 +#define SIZE_L3 (1 + MAX_NUMNODES) + +/* + * This function may be completely optimized away if + * a constant is passed to it. Mostly the same as + * what is in linux/slab.h except it returns an + * index. + */ +static inline int index_of(const size_t size) +{ + if (__builtin_constant_p(size)) { + int i = 0; + +#define CACHE(x) \ + if (size <=x) \ + return i; \ + else \ + i++; +#include "linux/kmalloc_sizes.h" +#undef CACHE + { + extern void __bad_size(void); + __bad_size(); + } } -#define list3_data(cachep) \ - (&(cachep)->lists) + return 0; +} + +#define INDEX_AC index_of(sizeof(struct arraycache_init)) +#define INDEX_L3 index_of(sizeof(struct kmem_list3)) + +static inline void kmem_list3_init(struct kmem_list3 *parent) +{ + INIT_LIST_HEAD(&parent->slabs_full); + INIT_LIST_HEAD(&parent->slabs_partial); + INIT_LIST_HEAD(&parent->slabs_free); + parent->shared = NULL; + parent->alien = NULL; + spin_lock_init(&parent->list_lock); + parent->free_objects = 0; + parent->free_touched = 0; +} -/* NUMA: per-node */ -#define list3_data_ptr(cachep, ptr) \ - list3_data(cachep) +#define MAKE_LIST(cachep, listp, slab, nodeid) \ + do { \ + INIT_LIST_HEAD(listp); \ + list_splice(&(cachep->nodelists[nodeid]->slab), listp); \ + } while (0) + +#define MAKE_ALL_LISTS(cachep, ptr, nodeid) \ + do { \ + MAKE_LIST((cachep), (&(ptr)->slabs_full), slabs_full, nodeid); \ + MAKE_LIST((cachep), (&(ptr)->slabs_partial), slabs_partial, nodeid); \ + MAKE_LIST((cachep), (&(ptr)->slabs_free), slabs_free, nodeid); \ + } while (0) /* * kmem_cache_t @@ -306,13 +372,12 @@ struct kmem_cache_s { struct array_cache *array[NR_CPUS]; unsigned int batchcount; unsigned int limit; -/* 2) touched by every alloc & free from the backend */ - struct kmem_list3 lists; - /* NUMA: kmem_3list_t *nodelists[MAX_NUMNODES] */ + unsigned int shared; unsigned int objsize; +/* 2) touched by every alloc & free from the backend */ + struct kmem_list3 *nodelists[MAX_NUMNODES]; unsigned int flags; /* constant flags */ unsigned int num; /* # of objs per slab */ - unsigned int free_limit; /* upper limit of objects in the lists */ spinlock_t spinlock; /* 3) cache_grow/shrink */ @@ -349,6 +414,7 @@ struct kmem_cache_s { unsigned long errors; unsigned long max_freeable; unsigned long node_allocs; + unsigned long node_frees; atomic_t allochit; atomic_t allocmiss; atomic_t freehit; @@ -384,6 +450,7 @@ struct kmem_cache_s { } while (0) #define STATS_INC_ERR(x) ((x)->errors++) #define STATS_INC_NODEALLOCS(x) ((x)->node_allocs++) +#define STATS_INC_NODEFREES(x) ((x)->node_frees++) #define STATS_SET_FREEABLE(x, i) \ do { if ((x)->max_freeable < i) \ (x)->max_freeable = i; \ @@ -402,6 +469,7 @@ struct kmem_cache_s { #define STATS_SET_HIGH(x) do { } while (0) #define STATS_INC_ERR(x) do { } while (0) #define STATS_INC_NODEALLOCS(x) do { } while (0) +#define STATS_INC_NODEFREES(x) do { } while (0) #define STATS_SET_FREEABLE(x, i) \ do { } while (0) @@ -534,9 +602,9 @@ static struct arraycache_init initarray_generic = /* internal cache of cache description objs */ static kmem_cache_t cache_cache = { - .lists = LIST3_INIT(cache_cache.lists), .batchcount = 1, .limit = BOOT_CPUCACHE_ENTRIES, + .shared = 1, .objsize = sizeof(kmem_cache_t), .flags = SLAB_NO_REAP, .spinlock = SPIN_LOCK_UNLOCKED, @@ -557,7 +625,6 @@ static struct list_head cache_chain; * SLAB_RECLAIM_ACCOUNT turns this on per-slab */ atomic_t slab_reclaim_pages; -EXPORT_SYMBOL(slab_reclaim_pages); /* * chicken and egg problem: delay the per-cpu array allocation @@ -565,7 +632,8 @@ EXPORT_SYMBOL(slab_reclaim_pages); */ static enum { NONE, - PARTIAL, + PARTIAL_AC, + PARTIAL_L3, FULL } g_cpucache_up; @@ -574,11 +642,7 @@ static DEFINE_PER_CPU(struct work_struct, reap_work); static void free_block(kmem_cache_t* cachep, void** objpp, int len); static void enable_cpucache (kmem_cache_t *cachep); static void cache_reap (void *unused); - -static inline void **ac_entry(struct array_cache *ac) -{ - return (void**)(ac+1); -} +static int __node_shrink(kmem_cache_t *cachep, int node); static inline struct array_cache *ac_data(kmem_cache_t *cachep) { @@ -676,48 +740,160 @@ static void __devinit start_cpu_timer(int cpu) } } -static struct array_cache *alloc_arraycache(int cpu, int entries, +static struct array_cache *alloc_arraycache(int node, int entries, int batchcount) { int memsize = sizeof(void*)*entries+sizeof(struct array_cache); struct array_cache *nc = NULL; - if (cpu == -1) - nc = kmalloc(memsize, GFP_KERNEL); - else - nc = kmalloc_node(memsize, GFP_KERNEL, cpu_to_node(cpu)); - + nc = kmalloc_node(memsize, GFP_KERNEL, node); if (nc) { nc->avail = 0; nc->limit = entries; nc->batchcount = batchcount; nc->touched = 0; + spin_lock_init(&nc->lock); } return nc; } +#ifdef CONFIG_NUMA +static inline struct array_cache **alloc_alien_cache(int node, int limit) +{ + struct array_cache **ac_ptr; + int memsize = sizeof(void*)*MAX_NUMNODES; + int i; + + if (limit > 1) + limit = 12; + ac_ptr = kmalloc_node(memsize, GFP_KERNEL, node); + if (ac_ptr) { + for_each_node(i) { + if (i == node || !node_online(i)) { + ac_ptr[i] = NULL; + continue; + } + ac_ptr[i] = alloc_arraycache(node, limit, 0xbaadf00d); + if (!ac_ptr[i]) { + for (i--; i <=0; i--) + kfree(ac_ptr[i]); + kfree(ac_ptr); + return NULL; + } + } + } + return ac_ptr; +} + +static inline void free_alien_cache(struct array_cache **ac_ptr) +{ + int i; + + if (!ac_ptr) + return; + + for_each_node(i) + kfree(ac_ptr[i]); + + kfree(ac_ptr); +} + +static inline void __drain_alien_cache(kmem_cache_t *cachep, struct array_cache *ac, int node) +{ + struct kmem_list3 *rl3 = cachep->nodelists[node]; + + if (ac->avail) { + spin_lock(&rl3->list_lock); + free_block(cachep, ac->entry, ac->avail); + ac->avail = 0; + spin_unlock(&rl3->list_lock); + } +} + +static void drain_alien_cache(kmem_cache_t *cachep, struct kmem_list3 *l3) +{ + int i=0; + struct array_cache *ac; + unsigned long flags; + + for_each_online_node(i) { + ac = l3->alien[i]; + if (ac) { + spin_lock_irqsave(&ac->lock, flags); + __drain_alien_cache(cachep, ac, i); + spin_unlock_irqrestore(&ac->lock, flags); + } + } +} +#else +#define alloc_alien_cache(node, limit) do { } while (0) +#define free_alien_cache(ac_ptr) do { } while (0) +#define drain_alien_cache(cachep, l3) do { } while (0) +#endif + static int __devinit cpuup_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { long cpu = (long)hcpu; kmem_cache_t* cachep; + struct kmem_list3 *l3 = NULL; + int node = cpu_to_node(cpu); + int memsize = sizeof(struct kmem_list3); + struct array_cache *nc = NULL; switch (action) { case CPU_UP_PREPARE: down(&cache_chain_sem); + /* we need to do this right in the beginning since + * alloc_arraycache's are going to use this list. + * kmalloc_node allows us to add the slab to the right + * kmem_list3 and not this cpu's kmem_list3 + */ + list_for_each_entry(cachep, &cache_chain, next) { - struct array_cache *nc; + /* setup the size64 kmemlist for cpu before we can + * begin anything. Make sure some other cpu on this + * node has not already allocated this + */ + if (!cachep->nodelists[node]) { + if (!(l3 = kmalloc_node(memsize, + GFP_KERNEL, node))) + goto bad; + kmem_list3_init(l3); + l3->next_reap = jiffies + REAPTIMEOUT_LIST3 + + ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + + cachep->nodelists[node] = l3; + } + + spin_lock_irq(&cachep->nodelists[node]->list_lock); + cachep->nodelists[node]->free_limit = + (1 + nr_cpus_node(node)) * + cachep->batchcount + cachep->num; + spin_unlock_irq(&cachep->nodelists[node]->list_lock); + } - nc = alloc_arraycache(cpu, cachep->limit, cachep->batchcount); + /* Now we can go ahead with allocating the shared array's + & array cache's */ + list_for_each_entry(cachep, &cache_chain, next) { + nc = alloc_arraycache(node, cachep->limit, + cachep->batchcount); if (!nc) goto bad; - - spin_lock_irq(&cachep->spinlock); cachep->array[cpu] = nc; - cachep->free_limit = (1+num_online_cpus())*cachep->batchcount - + cachep->num; - spin_unlock_irq(&cachep->spinlock); + l3 = cachep->nodelists[node]; + BUG_ON(!l3); + if (!l3->shared) { + if (!(nc = alloc_arraycache(node, + cachep->shared*cachep->batchcount, + 0xbaadf00d))) + goto bad; + + /* we are serialised from CPU_DEAD or + CPU_UP_CANCELLED by the cpucontrol lock */ + l3->shared = nc; + } } up(&cache_chain_sem); break; @@ -732,13 +908,51 @@ static int __devinit cpuup_callback(struct notifier_block *nfb, list_for_each_entry(cachep, &cache_chain, next) { struct array_cache *nc; + cpumask_t mask; + mask = node_to_cpumask(node); spin_lock_irq(&cachep->spinlock); /* cpu is dead; no one can alloc from it. */ nc = cachep->array[cpu]; cachep->array[cpu] = NULL; - cachep->free_limit -= cachep->batchcount; - free_block(cachep, ac_entry(nc), nc->avail); + l3 = cachep->nodelists[node]; + + if (!l3) + goto unlock_cache; + + spin_lock(&l3->list_lock); + + /* Free limit for this kmem_list3 */ + l3->free_limit -= cachep->batchcount; + if (nc) + free_block(cachep, nc->entry, nc->avail); + + if (!cpus_empty(mask)) { + spin_unlock(&l3->list_lock); + goto unlock_cache; + } + + if (l3->shared) { + free_block(cachep, l3->shared->entry, + l3->shared->avail); + kfree(l3->shared); + l3->shared = NULL; + } + if (l3->alien) { + drain_alien_cache(cachep, l3); + free_alien_cache(l3->alien); + l3->alien = NULL; + } + + /* free slabs belonging to this node */ + if (__node_shrink(cachep, node)) { + cachep->nodelists[node] = NULL; + spin_unlock(&l3->list_lock); + kfree(l3); + } else { + spin_unlock(&l3->list_lock); + } +unlock_cache: spin_unlock_irq(&cachep->spinlock); kfree(nc); } @@ -754,6 +968,25 @@ static int __devinit cpuup_callback(struct notifier_block *nfb, static struct notifier_block cpucache_notifier = { &cpuup_callback, NULL, 0 }; +/* + * swap the static kmem_list3 with kmalloced memory + */ +static void init_list(kmem_cache_t *cachep, struct kmem_list3 *list, + int nodeid) +{ + struct kmem_list3 *ptr; + + BUG_ON(cachep->nodelists[nodeid] != list); + ptr = kmalloc_node(sizeof(struct kmem_list3), GFP_KERNEL, nodeid); + BUG_ON(!ptr); + + local_irq_disable(); + memcpy(ptr, list, sizeof(struct kmem_list3)); + MAKE_ALL_LISTS(cachep, ptr, nodeid); + cachep->nodelists[nodeid] = ptr; + local_irq_enable(); +} + /* Initialisation. * Called after the gfp() functions have been enabled, and before smp_init(). */ @@ -762,6 +995,13 @@ void __init kmem_cache_init(void) size_t left_over; struct cache_sizes *sizes; struct cache_names *names; + int i; + + for (i = 0; i < NUM_INIT_LISTS; i++) { + kmem_list3_init(&initkmem_list3[i]); + if (i < MAX_NUMNODES) + cache_cache.nodelists[i] = NULL; + } /* * Fragmentation resistance on low memory - only use bigger @@ -770,21 +1010,24 @@ void __init kmem_cache_init(void) if (num_physpages > (32 << 20) >> PAGE_SHIFT) slab_break_gfp_order = BREAK_GFP_ORDER_HI; - /* Bootstrap is tricky, because several objects are allocated * from caches that do not exist yet: * 1) initialize the cache_cache cache: it contains the kmem_cache_t * structures of all caches, except cache_cache itself: cache_cache * is statically allocated. - * Initially an __init data area is used for the head array, it's - * replaced with a kmalloc allocated array at the end of the bootstrap. + * Initially an __init data area is used for the head array and the + * kmem_list3 structures, it's replaced with a kmalloc allocated + * array at the end of the bootstrap. * 2) Create the first kmalloc cache. - * The kmem_cache_t for the new cache is allocated normally. An __init - * data area is used for the head array. - * 3) Create the remaining kmalloc caches, with minimally sized head arrays. + * The kmem_cache_t for the new cache is allocated normally. + * An __init data area is used for the head array. + * 3) Create the remaining kmalloc caches, with minimally sized + * head arrays. * 4) Replace the __init data head arrays for cache_cache and the first * kmalloc cache with kmalloc allocated arrays. - * 5) Resize the head arrays of the kmalloc caches to their final sizes. + * 5) Replace the __init data for kmem_list3 for cache_cache and + * the other cache's with kmalloc allocated memory. + * 6) Resize the head arrays of the kmalloc caches to their final sizes. */ /* 1) create the cache_cache */ @@ -793,6 +1036,7 @@ void __init kmem_cache_init(void) list_add(&cache_cache.next, &cache_chain); cache_cache.colour_off = cache_line_size(); cache_cache.array[smp_processor_id()] = &initarray_cache.cache; + cache_cache.nodelists[numa_node_id()] = &initkmem_list3[CACHE_CACHE]; cache_cache.objsize = ALIGN(cache_cache.objsize, cache_line_size()); @@ -810,15 +1054,33 @@ void __init kmem_cache_init(void) sizes = malloc_sizes; names = cache_names; + /* Initialize the caches that provide memory for the array cache + * and the kmem_list3 structures first. + * Without this, further allocations will bug + */ + + sizes[INDEX_AC].cs_cachep = kmem_cache_create(names[INDEX_AC].name, + sizes[INDEX_AC].cs_size, ARCH_KMALLOC_MINALIGN, + (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL); + + if (INDEX_AC != INDEX_L3) + sizes[INDEX_L3].cs_cachep = + kmem_cache_create(names[INDEX_L3].name, + sizes[INDEX_L3].cs_size, ARCH_KMALLOC_MINALIGN, + (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL); + while (sizes->cs_size != ULONG_MAX) { - /* For performance, all the general caches are L1 aligned. + /* + * For performance, all the general caches are L1 aligned. * This should be particularly beneficial on SMP boxes, as it * eliminates "false sharing". * Note for systems short on memory removing the alignment will - * allow tighter packing of the smaller caches. */ - sizes->cs_cachep = kmem_cache_create(names->name, - sizes->cs_size, ARCH_KMALLOC_MINALIGN, - (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL); + * allow tighter packing of the smaller caches. + */ + if(!sizes->cs_cachep) + sizes->cs_cachep = kmem_cache_create(names->name, + sizes->cs_size, ARCH_KMALLOC_MINALIGN, + (ARCH_KMALLOC_FLAGS | SLAB_PANIC), NULL, NULL); /* Inc off-slab bufctl limit until the ceiling is hit. */ if (!(OFF_SLAB(sizes->cs_cachep))) { @@ -837,24 +1099,47 @@ void __init kmem_cache_init(void) /* 4) Replace the bootstrap head arrays */ { void * ptr; - + ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL); + local_irq_disable(); BUG_ON(ac_data(&cache_cache) != &initarray_cache.cache); - memcpy(ptr, ac_data(&cache_cache), sizeof(struct arraycache_init)); + memcpy(ptr, ac_data(&cache_cache), + sizeof(struct arraycache_init)); cache_cache.array[smp_processor_id()] = ptr; local_irq_enable(); - + ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL); + local_irq_disable(); - BUG_ON(ac_data(malloc_sizes[0].cs_cachep) != &initarray_generic.cache); - memcpy(ptr, ac_data(malloc_sizes[0].cs_cachep), + BUG_ON(ac_data(malloc_sizes[INDEX_AC].cs_cachep) + != &initarray_generic.cache); + memcpy(ptr, ac_data(malloc_sizes[INDEX_AC].cs_cachep), sizeof(struct arraycache_init)); - malloc_sizes[0].cs_cachep->array[smp_processor_id()] = ptr; + malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] = + ptr; local_irq_enable(); } + /* 5) Replace the bootstrap kmem_list3's */ + { + int node; + /* Replace the static kmem_list3 structures for the boot cpu */ + init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], + numa_node_id()); + + for_each_online_node(node) { + init_list(malloc_sizes[INDEX_AC].cs_cachep, + &initkmem_list3[SIZE_AC+node], node); + + if (INDEX_AC != INDEX_L3) { + init_list(malloc_sizes[INDEX_L3].cs_cachep, + &initkmem_list3[SIZE_L3+node], + node); + } + } + } - /* 5) resize the head arrays to their final sizes */ + /* 6) resize the head arrays to their final sizes */ { kmem_cache_t *cachep; down(&cache_chain_sem); @@ -870,7 +1155,6 @@ void __init kmem_cache_init(void) * that initializes ac_data for all new cpus */ register_cpu_notifier(&cpucache_notifier); - /* The reap timers are started later, with a module init call: * That part of the kernel is not yet operational. @@ -885,10 +1169,8 @@ static int __init cpucache_init(void) * Register the timers that return unneeded * pages to gfp. */ - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (cpu_online(cpu)) - start_cpu_timer(cpu); - } + for_each_online_cpu(cpu) + start_cpu_timer(cpu); return 0; } @@ -1167,6 +1449,20 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp) } } +/* For setting up all the kmem_list3s for cache whose objsize is same + as size of kmem_list3. */ +static inline void set_up_list3s(kmem_cache_t *cachep, int index) +{ + int node; + + for_each_online_node(node) { + cachep->nodelists[node] = &initkmem_list3[index+node]; + cachep->nodelists[node]->next_reap = jiffies + + REAPTIMEOUT_LIST3 + + ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + } +} + /** * kmem_cache_create - Create a cache. * @name: A string which is used in /proc/slabinfo to identify this cache. @@ -1320,7 +1616,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, size += BYTES_PER_WORD; } #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC) - if (size > 128 && cachep->reallen > cache_line_size() && size < PAGE_SIZE) { + if (size >= malloc_sizes[INDEX_L3+1].cs_size && cachep->reallen > cache_line_size() && size < PAGE_SIZE) { cachep->dbghead += PAGE_SIZE - size; size = PAGE_SIZE; } @@ -1422,10 +1718,6 @@ kmem_cache_create (const char *name, size_t size, size_t align, cachep->gfpflags |= GFP_DMA; spin_lock_init(&cachep->spinlock); cachep->objsize = size; - /* NUMA */ - INIT_LIST_HEAD(&cachep->lists.slabs_full); - INIT_LIST_HEAD(&cachep->lists.slabs_partial); - INIT_LIST_HEAD(&cachep->lists.slabs_free); if (flags & CFLGS_OFF_SLAB) cachep->slabp_cache = kmem_find_general_cachep(slab_size,0); @@ -1444,11 +1736,43 @@ kmem_cache_create (const char *name, size_t size, size_t align, * the cache that's used by kmalloc(24), otherwise * the creation of further caches will BUG(). */ - cachep->array[smp_processor_id()] = &initarray_generic.cache; - g_cpucache_up = PARTIAL; + cachep->array[smp_processor_id()] = + &initarray_generic.cache; + + /* If the cache that's used by + * kmalloc(sizeof(kmem_list3)) is the first cache, + * then we need to set up all its list3s, otherwise + * the creation of further caches will BUG(). + */ + set_up_list3s(cachep, SIZE_AC); + if (INDEX_AC == INDEX_L3) + g_cpucache_up = PARTIAL_L3; + else + g_cpucache_up = PARTIAL_AC; } else { - cachep->array[smp_processor_id()] = kmalloc(sizeof(struct arraycache_init),GFP_KERNEL); + cachep->array[smp_processor_id()] = + kmalloc(sizeof(struct arraycache_init), + GFP_KERNEL); + + if (g_cpucache_up == PARTIAL_AC) { + set_up_list3s(cachep, SIZE_L3); + g_cpucache_up = PARTIAL_L3; + } else { + int node; + for_each_online_node(node) { + + cachep->nodelists[node] = + kmalloc_node(sizeof(struct kmem_list3), + GFP_KERNEL, node); + BUG_ON(!cachep->nodelists[node]); + kmem_list3_init(cachep->nodelists[node]); + } + } } + cachep->nodelists[numa_node_id()]->next_reap = + jiffies + REAPTIMEOUT_LIST3 + + ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + BUG_ON(!ac_data(cachep)); ac_data(cachep)->avail = 0; ac_data(cachep)->limit = BOOT_CPUCACHE_ENTRIES; @@ -1456,13 +1780,8 @@ kmem_cache_create (const char *name, size_t size, size_t align, ac_data(cachep)->touched = 0; cachep->batchcount = 1; cachep->limit = BOOT_CPUCACHE_ENTRIES; - cachep->free_limit = (1+num_online_cpus())*cachep->batchcount - + cachep->num; } - cachep->lists.next_reap = jiffies + REAPTIMEOUT_LIST3 + - ((unsigned long)cachep)%REAPTIMEOUT_LIST3; - /* Need the semaphore to access the chain. */ down(&cache_chain_sem); { @@ -1519,13 +1838,23 @@ static void check_spinlock_acquired(kmem_cache_t *cachep) { #ifdef CONFIG_SMP check_irq_off(); - BUG_ON(spin_trylock(&cachep->spinlock)); + assert_spin_locked(&cachep->nodelists[numa_node_id()]->list_lock); #endif } + +static inline void check_spinlock_acquired_node(kmem_cache_t *cachep, int node) +{ +#ifdef CONFIG_SMP + check_irq_off(); + assert_spin_locked(&cachep->nodelists[node]->list_lock); +#endif +} + #else #define check_irq_off() do { } while(0) #define check_irq_on() do { } while(0) #define check_spinlock_acquired(x) do { } while(0) +#define check_spinlock_acquired_node(x, y) do { } while(0) #endif /* @@ -1547,7 +1876,7 @@ static void smp_call_function_all_cpus(void (*func) (void *arg), void *arg) } static void drain_array_locked(kmem_cache_t* cachep, - struct array_cache *ac, int force); + struct array_cache *ac, int force, int node); static void do_drain(void *arg) { @@ -1556,59 +1885,82 @@ static void do_drain(void *arg) check_irq_off(); ac = ac_data(cachep); - spin_lock(&cachep->spinlock); - free_block(cachep, &ac_entry(ac)[0], ac->avail); - spin_unlock(&cachep->spinlock); + spin_lock(&cachep->nodelists[numa_node_id()]->list_lock); + free_block(cachep, ac->entry, ac->avail); + spin_unlock(&cachep->nodelists[numa_node_id()]->list_lock); ac->avail = 0; } static void drain_cpu_caches(kmem_cache_t *cachep) { + struct kmem_list3 *l3; + int node; + smp_call_function_all_cpus(do_drain, cachep); check_irq_on(); spin_lock_irq(&cachep->spinlock); - if (cachep->lists.shared) - drain_array_locked(cachep, cachep->lists.shared, 1); + for_each_online_node(node) { + l3 = cachep->nodelists[node]; + if (l3) { + spin_lock(&l3->list_lock); + drain_array_locked(cachep, l3->shared, 1, node); + spin_unlock(&l3->list_lock); + if (l3->alien) + drain_alien_cache(cachep, l3); + } + } spin_unlock_irq(&cachep->spinlock); } - -/* NUMA shrink all list3s */ -static int __cache_shrink(kmem_cache_t *cachep) +static int __node_shrink(kmem_cache_t *cachep, int node) { struct slab *slabp; + struct kmem_list3 *l3 = cachep->nodelists[node]; int ret; - drain_cpu_caches(cachep); - - check_irq_on(); - spin_lock_irq(&cachep->spinlock); - - for(;;) { + for (;;) { struct list_head *p; - p = cachep->lists.slabs_free.prev; - if (p == &cachep->lists.slabs_free) + p = l3->slabs_free.prev; + if (p == &l3->slabs_free) break; - slabp = list_entry(cachep->lists.slabs_free.prev, struct slab, list); + slabp = list_entry(l3->slabs_free.prev, struct slab, list); #if DEBUG if (slabp->inuse) BUG(); #endif list_del(&slabp->list); - cachep->lists.free_objects -= cachep->num; - spin_unlock_irq(&cachep->spinlock); + l3->free_objects -= cachep->num; + spin_unlock_irq(&l3->list_lock); slab_destroy(cachep, slabp); - spin_lock_irq(&cachep->spinlock); + spin_lock_irq(&l3->list_lock); } - ret = !list_empty(&cachep->lists.slabs_full) || - !list_empty(&cachep->lists.slabs_partial); - spin_unlock_irq(&cachep->spinlock); + ret = !list_empty(&l3->slabs_full) || + !list_empty(&l3->slabs_partial); return ret; } +static int __cache_shrink(kmem_cache_t *cachep) +{ + int ret = 0, i = 0; + struct kmem_list3 *l3; + + drain_cpu_caches(cachep); + + check_irq_on(); + for_each_online_node(i) { + l3 = cachep->nodelists[i]; + if (l3) { + spin_lock_irq(&l3->list_lock); + ret += __node_shrink(cachep, i); + spin_unlock_irq(&l3->list_lock); + } + } + return (ret ? 1 : 0); +} + /** * kmem_cache_shrink - Shrink a cache. * @cachep: The cache to shrink. @@ -1645,6 +1997,7 @@ EXPORT_SYMBOL(kmem_cache_shrink); int kmem_cache_destroy(kmem_cache_t * cachep) { int i; + struct kmem_list3 *l3; if (!cachep || in_interrupt()) BUG(); @@ -1672,15 +2025,17 @@ int kmem_cache_destroy(kmem_cache_t * cachep) if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) synchronize_rcu(); - /* no cpu_online check required here since we clear the percpu - * array on cpu offline and set this to NULL. - */ - for (i = 0; i < NR_CPUS; i++) + for_each_online_cpu(i) kfree(cachep->array[i]); /* NUMA: free the list3 structures */ - kfree(cachep->lists.shared); - cachep->lists.shared = NULL; + for_each_online_node(i) { + if ((l3 = cachep->nodelists[i])) { + kfree(l3->shared); + free_alien_cache(l3->alien); + kfree(l3); + } + } kmem_cache_free(&cache_cache, cachep); unlock_cpu_hotplug(); @@ -1690,8 +2045,8 @@ int kmem_cache_destroy(kmem_cache_t * cachep) EXPORT_SYMBOL(kmem_cache_destroy); /* Get the memory for a slab management obj. */ -static struct slab* alloc_slabmgmt(kmem_cache_t *cachep, - void *objp, int colour_off, unsigned int __nocast local_flags) +static struct slab* alloc_slabmgmt(kmem_cache_t *cachep, void *objp, + int colour_off, unsigned int __nocast local_flags) { struct slab *slabp; @@ -1722,7 +2077,7 @@ static void cache_init_objs(kmem_cache_t *cachep, int i; for (i = 0; i < cachep->num; i++) { - void* objp = slabp->s_mem+cachep->objsize*i; + void *objp = slabp->s_mem+cachep->objsize*i; #if DEBUG /* need to poison the objs? */ if (cachep->flags & SLAB_POISON) @@ -1799,6 +2154,7 @@ static int cache_grow(kmem_cache_t *cachep, unsigned int __nocast flags, int nod size_t offset; unsigned int local_flags; unsigned long ctor_flags; + struct kmem_list3 *l3; /* Be lazy and only check for valid flags here, * keeping it out of the critical path in kmem_cache_alloc(). @@ -1830,6 +2186,7 @@ static int cache_grow(kmem_cache_t *cachep, unsigned int __nocast flags, int nod spin_unlock(&cachep->spinlock); + check_irq_off(); if (local_flags & __GFP_WAIT) local_irq_enable(); @@ -1841,8 +2198,9 @@ static int cache_grow(kmem_cache_t *cachep, unsigned int __nocast flags, int nod */ kmem_flagcheck(cachep, flags); - - /* Get mem for the objs. */ + /* Get mem for the objs. + * Attempt to allocate a physical page from 'nodeid', + */ if (!(objp = kmem_getpages(cachep, flags, nodeid))) goto failed; @@ -1850,6 +2208,7 @@ static int cache_grow(kmem_cache_t *cachep, unsigned int __nocast flags, int nod if (!(slabp = alloc_slabmgmt(cachep, objp, offset, local_flags))) goto opps1; + slabp->nodeid = nodeid; set_slab_attr(cachep, slabp, objp); cache_init_objs(cachep, slabp, ctor_flags); @@ -1857,13 +2216,14 @@ static int cache_grow(kmem_cache_t *cachep, unsigned int __nocast flags, int nod if (local_flags & __GFP_WAIT) local_irq_disable(); check_irq_off(); - spin_lock(&cachep->spinlock); + l3 = cachep->nodelists[nodeid]; + spin_lock(&l3->list_lock); /* Make slab active. */ - list_add_tail(&slabp->list, &(list3_data(cachep)->slabs_free)); + list_add_tail(&slabp->list, &(l3->slabs_free)); STATS_INC_GROWN(cachep); - list3_data(cachep)->free_objects += cachep->num; - spin_unlock(&cachep->spinlock); + l3->free_objects += cachep->num; + spin_unlock(&l3->list_lock); return 1; opps1: kmem_freepages(cachep, objp); @@ -1969,7 +2329,6 @@ static void check_slabp(kmem_cache_t *cachep, struct slab *slabp) kmem_bufctl_t i; int entries = 0; - check_spinlock_acquired(cachep); /* Check slab's freelist to see if this obj is there. */ for (i = slabp->free; i != BUFCTL_END; i = slab_bufctl(slabp)[i]) { entries++; @@ -2012,10 +2371,11 @@ static void *cache_alloc_refill(kmem_cache_t *cachep, unsigned int __nocast flag */ batchcount = BATCHREFILL_LIMIT; } - l3 = list3_data(cachep); + l3 = cachep->nodelists[numa_node_id()]; + + BUG_ON(ac->avail > 0 || !l3); + spin_lock(&l3->list_lock); - BUG_ON(ac->avail > 0); - spin_lock(&cachep->spinlock); if (l3->shared) { struct array_cache *shared_array = l3->shared; if (shared_array->avail) { @@ -2023,8 +2383,9 @@ static void *cache_alloc_refill(kmem_cache_t *cachep, unsigned int __nocast flag batchcount = shared_array->avail; shared_array->avail -= batchcount; ac->avail = batchcount; - memcpy(ac_entry(ac), &ac_entry(shared_array)[shared_array->avail], - sizeof(void*)*batchcount); + memcpy(ac->entry, + &(shared_array->entry[shared_array->avail]), + sizeof(void*)*batchcount); shared_array->touched = 1; goto alloc_done; } @@ -2051,7 +2412,8 @@ static void *cache_alloc_refill(kmem_cache_t *cachep, unsigned int __nocast flag STATS_SET_HIGH(cachep); /* get obj pointer */ - ac_entry(ac)[ac->avail++] = slabp->s_mem + slabp->free*cachep->objsize; + ac->entry[ac->avail++] = slabp->s_mem + + slabp->free*cachep->objsize; slabp->inuse++; next = slab_bufctl(slabp)[slabp->free]; @@ -2073,12 +2435,12 @@ static void *cache_alloc_refill(kmem_cache_t *cachep, unsigned int __nocast flag must_grow: l3->free_objects -= ac->avail; alloc_done: - spin_unlock(&cachep->spinlock); + spin_unlock(&l3->list_lock); if (unlikely(!ac->avail)) { int x; - x = cache_grow(cachep, flags, -1); - + x = cache_grow(cachep, flags, numa_node_id()); + // cache_grow can reenable interrupts, then ac could change. ac = ac_data(cachep); if (!x && ac->avail == 0) // no objects in sight? abort @@ -2088,7 +2450,7 @@ static void *cache_alloc_refill(kmem_cache_t *cachep, unsigned int __nocast flag goto retry; } ac->touched = 1; - return ac_entry(ac)[--ac->avail]; + return ac->entry[--ac->avail]; } static inline void @@ -2160,7 +2522,7 @@ static inline void *__cache_alloc(kmem_cache_t *cachep, unsigned int __nocast fl if (likely(ac->avail)) { STATS_INC_ALLOCHIT(cachep); ac->touched = 1; - objp = ac_entry(ac)[--ac->avail]; + objp = ac->entry[--ac->avail]; } else { STATS_INC_ALLOCMISS(cachep); objp = cache_alloc_refill(cachep, flags); @@ -2172,33 +2534,104 @@ static inline void *__cache_alloc(kmem_cache_t *cachep, unsigned int __nocast fl return objp; } -/* - * NUMA: different approach needed if the spinlock is moved into - * the l3 structure +#ifdef CONFIG_NUMA +/* + * A interface to enable slab creation on nodeid */ +static void *__cache_alloc_node(kmem_cache_t *cachep, int flags, int nodeid) +{ + struct list_head *entry; + struct slab *slabp; + struct kmem_list3 *l3; + void *obj; + kmem_bufctl_t next; + int x; + + l3 = cachep->nodelists[nodeid]; + BUG_ON(!l3); + +retry: + spin_lock(&l3->list_lock); + entry = l3->slabs_partial.next; + if (entry == &l3->slabs_partial) { + l3->free_touched = 1; + entry = l3->slabs_free.next; + if (entry == &l3->slabs_free) + goto must_grow; + } + + slabp = list_entry(entry, struct slab, list); + check_spinlock_acquired_node(cachep, nodeid); + check_slabp(cachep, slabp); + + STATS_INC_NODEALLOCS(cachep); + STATS_INC_ACTIVE(cachep); + STATS_SET_HIGH(cachep); + + BUG_ON(slabp->inuse == cachep->num); + + /* get obj pointer */ + obj = slabp->s_mem + slabp->free*cachep->objsize; + slabp->inuse++; + next = slab_bufctl(slabp)[slabp->free]; +#if DEBUG + slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE; +#endif + slabp->free = next; + check_slabp(cachep, slabp); + l3->free_objects--; + /* move slabp to correct slabp list: */ + list_del(&slabp->list); + + if (slabp->free == BUFCTL_END) { + list_add(&slabp->list, &l3->slabs_full); + } else { + list_add(&slabp->list, &l3->slabs_partial); + } + + spin_unlock(&l3->list_lock); + goto done; + +must_grow: + spin_unlock(&l3->list_lock); + x = cache_grow(cachep, flags, nodeid); + if (!x) + return NULL; + + goto retry; +done: + return obj; +} +#endif + +/* + * Caller needs to acquire correct kmem_list's list_lock + */ static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects) { int i; - - check_spinlock_acquired(cachep); - - /* NUMA: move add into loop */ - cachep->lists.free_objects += nr_objects; + struct kmem_list3 *l3; for (i = 0; i < nr_objects; i++) { void *objp = objpp[i]; struct slab *slabp; unsigned int objnr; + int nodeid = 0; slabp = GET_PAGE_SLAB(virt_to_page(objp)); + nodeid = slabp->nodeid; + l3 = cachep->nodelists[nodeid]; list_del(&slabp->list); objnr = (objp - slabp->s_mem) / cachep->objsize; + check_spinlock_acquired_node(cachep, nodeid); check_slabp(cachep, slabp); + + #if DEBUG if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) { - printk(KERN_ERR "slab: double free detected in cache '%s', objp %p.\n", - cachep->name, objp); + printk(KERN_ERR "slab: double free detected in cache " + "'%s', objp %p\n", cachep->name, objp); BUG(); } #endif @@ -2206,24 +2639,23 @@ static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects) slabp->free = objnr; STATS_DEC_ACTIVE(cachep); slabp->inuse--; + l3->free_objects++; check_slabp(cachep, slabp); /* fixup slab chains */ if (slabp->inuse == 0) { - if (cachep->lists.free_objects > cachep->free_limit) { - cachep->lists.free_objects -= cachep->num; + if (l3->free_objects > l3->free_limit) { + l3->free_objects -= cachep->num; slab_destroy(cachep, slabp); } else { - list_add(&slabp->list, - &list3_data_ptr(cachep, objp)->slabs_free); + list_add(&slabp->list, &l3->slabs_free); } } else { /* Unconditionally move a slab to the end of the * partial list on free - maximum time for the * other objects to be freed, too. */ - list_add_tail(&slabp->list, - &list3_data_ptr(cachep, objp)->slabs_partial); + list_add_tail(&slabp->list, &l3->slabs_partial); } } } @@ -2231,36 +2663,38 @@ static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects) static void cache_flusharray(kmem_cache_t *cachep, struct array_cache *ac) { int batchcount; + struct kmem_list3 *l3; batchcount = ac->batchcount; #if DEBUG BUG_ON(!batchcount || batchcount > ac->avail); #endif check_irq_off(); - spin_lock(&cachep->spinlock); - if (cachep->lists.shared) { - struct array_cache *shared_array = cachep->lists.shared; + l3 = cachep->nodelists[numa_node_id()]; + spin_lock(&l3->list_lock); + if (l3->shared) { + struct array_cache *shared_array = l3->shared; int max = shared_array->limit-shared_array->avail; if (max) { if (batchcount > max) batchcount = max; - memcpy(&ac_entry(shared_array)[shared_array->avail], - &ac_entry(ac)[0], + memcpy(&(shared_array->entry[shared_array->avail]), + ac->entry, sizeof(void*)*batchcount); shared_array->avail += batchcount; goto free_done; } } - free_block(cachep, &ac_entry(ac)[0], batchcount); + free_block(cachep, ac->entry, batchcount); free_done: #if STATS { int i = 0; struct list_head *p; - p = list3_data(cachep)->slabs_free.next; - while (p != &(list3_data(cachep)->slabs_free)) { + p = l3->slabs_free.next; + while (p != &(l3->slabs_free)) { struct slab *slabp; slabp = list_entry(p, struct slab, list); @@ -2272,12 +2706,13 @@ static void cache_flusharray(kmem_cache_t *cachep, struct array_cache *ac) STATS_SET_FREEABLE(cachep, i); } #endif - spin_unlock(&cachep->spinlock); + spin_unlock(&l3->list_lock); ac->avail -= batchcount; - memmove(&ac_entry(ac)[0], &ac_entry(ac)[batchcount], + memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void*)*ac->avail); } + /* * __cache_free * Release an obj back to its cache. If the obj has a constructed @@ -2292,14 +2727,46 @@ static inline void __cache_free(kmem_cache_t *cachep, void *objp) check_irq_off(); objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0)); + /* Make sure we are not freeing a object from another + * node to the array cache on this cpu. + */ +#ifdef CONFIG_NUMA + { + struct slab *slabp; + slabp = GET_PAGE_SLAB(virt_to_page(objp)); + if (unlikely(slabp->nodeid != numa_node_id())) { + struct array_cache *alien = NULL; + int nodeid = slabp->nodeid; + struct kmem_list3 *l3 = cachep->nodelists[numa_node_id()]; + + STATS_INC_NODEFREES(cachep); + if (l3->alien && l3->alien[nodeid]) { + alien = l3->alien[nodeid]; + spin_lock(&alien->lock); + if (unlikely(alien->avail == alien->limit)) + __drain_alien_cache(cachep, + alien, nodeid); + alien->entry[alien->avail++] = objp; + spin_unlock(&alien->lock); + } else { + spin_lock(&(cachep->nodelists[nodeid])-> + list_lock); + free_block(cachep, &objp, 1); + spin_unlock(&(cachep->nodelists[nodeid])-> + list_lock); + } + return; + } + } +#endif if (likely(ac->avail < ac->limit)) { STATS_INC_FREEHIT(cachep); - ac_entry(ac)[ac->avail++] = objp; + ac->entry[ac->avail++] = objp; return; } else { STATS_INC_FREEMISS(cachep); cache_flusharray(cachep, ac); - ac_entry(ac)[ac->avail++] = objp; + ac->entry[ac->avail++] = objp; } } @@ -2369,81 +2836,30 @@ int fastcall kmem_ptr_validate(kmem_cache_t *cachep, void *ptr) * Identical to kmem_cache_alloc, except that this function is slow * and can sleep. And it will allocate memory on the given node, which * can improve the performance for cpu bound structures. + * New and improved: it will now make sure that the object gets + * put on the correct node list so that there is no false sharing. */ void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int nodeid) { - int loop; - void *objp; - struct slab *slabp; - kmem_bufctl_t next; - - if (nodeid == -1) - return kmem_cache_alloc(cachep, flags); - - for (loop = 0;;loop++) { - struct list_head *q; - - objp = NULL; - check_irq_on(); - spin_lock_irq(&cachep->spinlock); - /* walk through all partial and empty slab and find one - * from the right node */ - list_for_each(q,&cachep->lists.slabs_partial) { - slabp = list_entry(q, struct slab, list); - - if (page_to_nid(virt_to_page(slabp->s_mem)) == nodeid || - loop > 2) - goto got_slabp; - } - list_for_each(q, &cachep->lists.slabs_free) { - slabp = list_entry(q, struct slab, list); + unsigned long save_flags; + void *ptr; - if (page_to_nid(virt_to_page(slabp->s_mem)) == nodeid || - loop > 2) - goto got_slabp; - } - spin_unlock_irq(&cachep->spinlock); + if (nodeid == numa_node_id() || nodeid == -1) + return __cache_alloc(cachep, flags); - local_irq_disable(); - if (!cache_grow(cachep, flags, nodeid)) { - local_irq_enable(); - return NULL; - } - local_irq_enable(); + if (unlikely(!cachep->nodelists[nodeid])) { + /* Fall back to __cache_alloc if we run into trouble */ + printk(KERN_WARNING "slab: not allocating in inactive node %d for cache %s\n", nodeid, cachep->name); + return __cache_alloc(cachep,flags); } -got_slabp: - /* found one: allocate object */ - check_slabp(cachep, slabp); - check_spinlock_acquired(cachep); - STATS_INC_ALLOCED(cachep); - STATS_INC_ACTIVE(cachep); - STATS_SET_HIGH(cachep); - STATS_INC_NODEALLOCS(cachep); - - objp = slabp->s_mem + slabp->free*cachep->objsize; - - slabp->inuse++; - next = slab_bufctl(slabp)[slabp->free]; -#if DEBUG - slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE; -#endif - slabp->free = next; - check_slabp(cachep, slabp); - - /* move slabp to correct slabp list: */ - list_del(&slabp->list); - if (slabp->free == BUFCTL_END) - list_add(&slabp->list, &cachep->lists.slabs_full); - else - list_add(&slabp->list, &cachep->lists.slabs_partial); - - list3_data(cachep)->free_objects--; - spin_unlock_irq(&cachep->spinlock); + cache_alloc_debugcheck_before(cachep, flags); + local_irq_save(save_flags); + ptr = __cache_alloc_node(cachep, flags, nodeid); + local_irq_restore(save_flags); + ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, __builtin_return_address(0)); - objp = cache_alloc_debugcheck_after(cachep, GFP_KERNEL, objp, - __builtin_return_address(0)); - return objp; + return ptr; } EXPORT_SYMBOL(kmem_cache_alloc_node); @@ -2513,11 +2929,18 @@ void *__alloc_percpu(size_t size, size_t align) if (!pdata) return NULL; - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_possible(i)) - continue; - pdata->ptrs[i] = kmalloc_node(size, GFP_KERNEL, - cpu_to_node(i)); + /* + * Cannot use for_each_online_cpu since a cpu may come online + * and we have no way of figuring out how to fix the array + * that we have allocated then.... + */ + for_each_cpu(i) { + int node = cpu_to_node(i); + + if (node_online(node)) + pdata->ptrs[i] = kmalloc_node(size, GFP_KERNEL, node); + else + pdata->ptrs[i] = kmalloc(size, GFP_KERNEL); if (!pdata->ptrs[i]) goto unwind_oom; @@ -2607,11 +3030,11 @@ free_percpu(const void *objp) int i; struct percpu_data *p = (struct percpu_data *) (~(unsigned long) objp); - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_possible(i)) - continue; + /* + * We allocate for all cpus so we cannot use for online cpu here. + */ + for_each_cpu(i) kfree(p->ptrs[i]); - } kfree(p); } EXPORT_SYMBOL(free_percpu); @@ -2629,6 +3052,64 @@ const char *kmem_cache_name(kmem_cache_t *cachep) } EXPORT_SYMBOL_GPL(kmem_cache_name); +/* + * This initializes kmem_list3 for all nodes. + */ +static int alloc_kmemlist(kmem_cache_t *cachep) +{ + int node; + struct kmem_list3 *l3; + int err = 0; + + for_each_online_node(node) { + struct array_cache *nc = NULL, *new; + struct array_cache **new_alien = NULL; +#ifdef CONFIG_NUMA + if (!(new_alien = alloc_alien_cache(node, cachep->limit))) + goto fail; +#endif + if (!(new = alloc_arraycache(node, (cachep->shared* + cachep->batchcount), 0xbaadf00d))) + goto fail; + if ((l3 = cachep->nodelists[node])) { + + spin_lock_irq(&l3->list_lock); + + if ((nc = cachep->nodelists[node]->shared)) + free_block(cachep, nc->entry, + nc->avail); + + l3->shared = new; + if (!cachep->nodelists[node]->alien) { + l3->alien = new_alien; + new_alien = NULL; + } + l3->free_limit = (1 + nr_cpus_node(node))* + cachep->batchcount + cachep->num; + spin_unlock_irq(&l3->list_lock); + kfree(nc); + free_alien_cache(new_alien); + continue; + } + if (!(l3 = kmalloc_node(sizeof(struct kmem_list3), + GFP_KERNEL, node))) + goto fail; + + kmem_list3_init(l3); + l3->next_reap = jiffies + REAPTIMEOUT_LIST3 + + ((unsigned long)cachep)%REAPTIMEOUT_LIST3; + l3->shared = new; + l3->alien = new_alien; + l3->free_limit = (1 + nr_cpus_node(node))* + cachep->batchcount + cachep->num; + cachep->nodelists[node] = l3; + } + return err; +fail: + err = -ENOMEM; + return err; +} + struct ccupdate_struct { kmem_cache_t *cachep; struct array_cache *new[NR_CPUS]; @@ -2641,7 +3122,7 @@ static void do_ccupdate_local(void *info) check_irq_off(); old = ac_data(new->cachep); - + new->cachep->array[smp_processor_id()] = new->new[smp_processor_id()]; new->new[smp_processor_id()] = old; } @@ -2651,54 +3132,43 @@ static int do_tune_cpucache(kmem_cache_t *cachep, int limit, int batchcount, int shared) { struct ccupdate_struct new; - struct array_cache *new_shared; - int i; + int i, err; memset(&new.new,0,sizeof(new.new)); - for (i = 0; i < NR_CPUS; i++) { - if (cpu_online(i)) { - new.new[i] = alloc_arraycache(i, limit, batchcount); - if (!new.new[i]) { - for (i--; i >= 0; i--) kfree(new.new[i]); - return -ENOMEM; - } - } else { - new.new[i] = NULL; + for_each_online_cpu(i) { + new.new[i] = alloc_arraycache(cpu_to_node(i), limit, batchcount); + if (!new.new[i]) { + for (i--; i >= 0; i--) kfree(new.new[i]); + return -ENOMEM; } } new.cachep = cachep; smp_call_function_all_cpus(do_ccupdate_local, (void *)&new); - + check_irq_on(); spin_lock_irq(&cachep->spinlock); cachep->batchcount = batchcount; cachep->limit = limit; - cachep->free_limit = (1+num_online_cpus())*cachep->batchcount + cachep->num; + cachep->shared = shared; spin_unlock_irq(&cachep->spinlock); - for (i = 0; i < NR_CPUS; i++) { + for_each_online_cpu(i) { struct array_cache *ccold = new.new[i]; if (!ccold) continue; - spin_lock_irq(&cachep->spinlock); - free_block(cachep, ac_entry(ccold), ccold->avail); - spin_unlock_irq(&cachep->spinlock); + spin_lock_irq(&cachep->nodelists[cpu_to_node(i)]->list_lock); + free_block(cachep, ccold->entry, ccold->avail); + spin_unlock_irq(&cachep->nodelists[cpu_to_node(i)]->list_lock); kfree(ccold); } - new_shared = alloc_arraycache(-1, batchcount*shared, 0xbaadf00d); - if (new_shared) { - struct array_cache *old; - spin_lock_irq(&cachep->spinlock); - old = cachep->lists.shared; - cachep->lists.shared = new_shared; - if (old) - free_block(cachep, ac_entry(old), old->avail); - spin_unlock_irq(&cachep->spinlock); - kfree(old); + err = alloc_kmemlist(cachep); + if (err) { + printk(KERN_ERR "alloc_kmemlist failed for %s, error %d.\n", + cachep->name, -err); + BUG(); } - return 0; } @@ -2756,11 +3226,11 @@ static void enable_cpucache(kmem_cache_t *cachep) } static void drain_array_locked(kmem_cache_t *cachep, - struct array_cache *ac, int force) + struct array_cache *ac, int force, int node) { int tofree; - check_spinlock_acquired(cachep); + check_spinlock_acquired_node(cachep, node); if (ac->touched && !force) { ac->touched = 0; } else if (ac->avail) { @@ -2768,9 +3238,9 @@ static void drain_array_locked(kmem_cache_t *cachep, if (tofree > ac->avail) { tofree = (ac->avail+1)/2; } - free_block(cachep, ac_entry(ac), tofree); + free_block(cachep, ac->entry, tofree); ac->avail -= tofree; - memmove(&ac_entry(ac)[0], &ac_entry(ac)[tofree], + memmove(ac->entry, &(ac->entry[tofree]), sizeof(void*)*ac->avail); } } @@ -2789,6 +3259,7 @@ static void drain_array_locked(kmem_cache_t *cachep, static void cache_reap(void *unused) { struct list_head *walk; + struct kmem_list3 *l3; if (down_trylock(&cache_chain_sem)) { /* Give up. Setup the next iteration. */ @@ -2809,27 +3280,32 @@ static void cache_reap(void *unused) check_irq_on(); - spin_lock_irq(&searchp->spinlock); + l3 = searchp->nodelists[numa_node_id()]; + if (l3->alien) + drain_alien_cache(searchp, l3); + spin_lock_irq(&l3->list_lock); - drain_array_locked(searchp, ac_data(searchp), 0); + drain_array_locked(searchp, ac_data(searchp), 0, + numa_node_id()); - if(time_after(searchp->lists.next_reap, jiffies)) + if (time_after(l3->next_reap, jiffies)) goto next_unlock; - searchp->lists.next_reap = jiffies + REAPTIMEOUT_LIST3; + l3->next_reap = jiffies + REAPTIMEOUT_LIST3; - if (searchp->lists.shared) - drain_array_locked(searchp, searchp->lists.shared, 0); + if (l3->shared) + drain_array_locked(searchp, l3->shared, 0, + numa_node_id()); - if (searchp->lists.free_touched) { - searchp->lists.free_touched = 0; + if (l3->free_touched) { + l3->free_touched = 0; goto next_unlock; } - tofree = (searchp->free_limit+5*searchp->num-1)/(5*searchp->num); + tofree = (l3->free_limit+5*searchp->num-1)/(5*searchp->num); do { - p = list3_data(searchp)->slabs_free.next; - if (p == &(list3_data(searchp)->slabs_free)) + p = l3->slabs_free.next; + if (p == &(l3->slabs_free)) break; slabp = list_entry(p, struct slab, list); @@ -2842,13 +3318,13 @@ static void cache_reap(void *unused) * searchp cannot disappear, we hold * cache_chain_lock */ - searchp->lists.free_objects -= searchp->num; - spin_unlock_irq(&searchp->spinlock); + l3->free_objects -= searchp->num; + spin_unlock_irq(&l3->list_lock); slab_destroy(searchp, slabp); - spin_lock_irq(&searchp->spinlock); + spin_lock_irq(&l3->list_lock); } while(--tofree > 0); next_unlock: - spin_unlock_irq(&searchp->spinlock); + spin_unlock_irq(&l3->list_lock); next: cond_resched(); } @@ -2882,7 +3358,7 @@ static void *s_start(struct seq_file *m, loff_t *pos) seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>"); #if STATS seq_puts(m, " : globalstat <listallocs> <maxobjs> <grown> <reaped>" - " <error> <maxfreeable> <freelimit> <nodeallocs>"); + " <error> <maxfreeable> <nodeallocs> <remotefrees>"); seq_puts(m, " : cpustat <allochit> <allocmiss> <freehit> <freemiss>"); #endif seq_putc(m, '\n'); @@ -2917,39 +3393,53 @@ static int s_show(struct seq_file *m, void *p) unsigned long active_objs; unsigned long num_objs; unsigned long active_slabs = 0; - unsigned long num_slabs; - const char *name; + unsigned long num_slabs, free_objects = 0, shared_avail = 0; + const char *name; char *error = NULL; + int node; + struct kmem_list3 *l3; check_irq_on(); spin_lock_irq(&cachep->spinlock); active_objs = 0; num_slabs = 0; - list_for_each(q,&cachep->lists.slabs_full) { - slabp = list_entry(q, struct slab, list); - if (slabp->inuse != cachep->num && !error) - error = "slabs_full accounting error"; - active_objs += cachep->num; - active_slabs++; - } - list_for_each(q,&cachep->lists.slabs_partial) { - slabp = list_entry(q, struct slab, list); - if (slabp->inuse == cachep->num && !error) - error = "slabs_partial inuse accounting error"; - if (!slabp->inuse && !error) - error = "slabs_partial/inuse accounting error"; - active_objs += slabp->inuse; - active_slabs++; - } - list_for_each(q,&cachep->lists.slabs_free) { - slabp = list_entry(q, struct slab, list); - if (slabp->inuse && !error) - error = "slabs_free/inuse accounting error"; - num_slabs++; + for_each_online_node(node) { + l3 = cachep->nodelists[node]; + if (!l3) + continue; + + spin_lock(&l3->list_lock); + + list_for_each(q,&l3->slabs_full) { + slabp = list_entry(q, struct slab, list); + if (slabp->inuse != cachep->num && !error) + error = "slabs_full accounting error"; + active_objs += cachep->num; + active_slabs++; + } + list_for_each(q,&l3->slabs_partial) { + slabp = list_entry(q, struct slab, list); + if (slabp->inuse == cachep->num && !error) + error = "slabs_partial inuse accounting error"; + if (!slabp->inuse && !error) + error = "slabs_partial/inuse accounting error"; + active_objs += slabp->inuse; + active_slabs++; + } + list_for_each(q,&l3->slabs_free) { + slabp = list_entry(q, struct slab, list); + if (slabp->inuse && !error) + error = "slabs_free/inuse accounting error"; + num_slabs++; + } + free_objects += l3->free_objects; + shared_avail += l3->shared->avail; + + spin_unlock(&l3->list_lock); } num_slabs+=active_slabs; num_objs = num_slabs*cachep->num; - if (num_objs - active_objs != cachep->lists.free_objects && !error) + if (num_objs - active_objs != free_objects && !error) error = "free_objects accounting error"; name = cachep->name; @@ -2961,9 +3451,9 @@ static int s_show(struct seq_file *m, void *p) cachep->num, (1<<cachep->gfporder)); seq_printf(m, " : tunables %4u %4u %4u", cachep->limit, cachep->batchcount, - cachep->lists.shared->limit/cachep->batchcount); - seq_printf(m, " : slabdata %6lu %6lu %6u", - active_slabs, num_slabs, cachep->lists.shared->avail); + cachep->shared); + seq_printf(m, " : slabdata %6lu %6lu %6lu", + active_slabs, num_slabs, shared_avail); #if STATS { /* list3 stats */ unsigned long high = cachep->high_mark; @@ -2972,12 +3462,13 @@ static int s_show(struct seq_file *m, void *p) unsigned long reaped = cachep->reaped; unsigned long errors = cachep->errors; unsigned long max_freeable = cachep->max_freeable; - unsigned long free_limit = cachep->free_limit; unsigned long node_allocs = cachep->node_allocs; + unsigned long node_frees = cachep->node_frees; - seq_printf(m, " : globalstat %7lu %6lu %5lu %4lu %4lu %4lu %4lu %4lu", - allocs, high, grown, reaped, errors, - max_freeable, free_limit, node_allocs); + seq_printf(m, " : globalstat %7lu %6lu %5lu %4lu \ + %4lu %4lu %4lu %4lu", + allocs, high, grown, reaped, errors, + max_freeable, node_allocs, node_frees); } /* cpu stats */ { @@ -3056,9 +3547,10 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer, batchcount < 1 || batchcount > limit || shared < 0) { - res = -EINVAL; + res = 0; } else { - res = do_tune_cpucache(cachep, limit, batchcount, shared); + res = do_tune_cpucache(cachep, limit, + batchcount, shared); } break; } -- GitLab From a1938038dd7e4188a8663e49242fa77dd2adb7ed Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Fri, 9 Sep 2005 13:03:34 -0700 Subject: [PATCH 176/563] [PATCH] VIDEO_BT848: remove not required part of the help text Things that are already expressed through the dependencies don't have to be mentioned in the help text. Signed-off-by: Adrian Bunk <bunk@stusta.de> Cc: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Cc: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 16c85c081e6eb..077720c2b640b 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -22,9 +22,6 @@ config VIDEO_BT848 the Miro, Hauppauge and STB boards. Please read the material in <file:Documentation/video4linux/bttv/> for more information. - If you say Y or M here, you need to say Y or M to "I2C support" and - "I2C bit-banging interfaces" in the device drivers section. - To compile this driver as a module, choose M here: the module will be called bttv. -- GitLab From 793cf9e6a54c698e109a599c8b8e303658fcaae6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:37 -0700 Subject: [PATCH 177/563] [PATCH] v4l: common part Updates and tuner additions - Remove $Id CVS logs for V4L files - Included newer cards. - Added a new NEC protocol for ir based on pulse distance. - Enable ATSC support for DViCO FusionHDTV5 Gold. - Added tuner LG NTSC (TALN mini series). - Fixed tea5767 autodetection. - Resolve more tuner types. - Commented debug function removed from mainstream. - Remove comments from mainstream. Still on development tree. - linux/version dependencies removed. - BTSC Lang1 now is set to auto_stereo mode. - New tuner standby API. - i2c-core.c uses hexadecimal for the i2c address, so it should stay consistent. Signed-off-by: Uli Luckas <luckas@musoft.de> Signed-off-by: Mac Michaels <wmichaels1@earthlink.net> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Hermann Pitton <hermann.pitton@onlinehome.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/video4linux/CARDLIST.tuner | 1 + drivers/media/common/ir-common.c | 68 +++++++++++++++++++- drivers/media/video/btcx-risc.c | 1 - drivers/media/video/btcx-risc.h | 1 - drivers/media/video/ir-kbd-gpio.c | 1 - drivers/media/video/ir-kbd-i2c.c | 1 - drivers/media/video/msp3400.h | 1 - drivers/media/video/mt20xx.c | 2 +- drivers/media/video/tda8290.c | 19 +++++- drivers/media/video/tda9887.c | 39 +++++++----- drivers/media/video/tea5767.c | 37 ++++++----- drivers/media/video/tuner-core.c | 79 ++++++++++++++---------- drivers/media/video/tuner-simple.c | 5 +- drivers/media/video/tveeprom.c | 25 ++------ drivers/media/video/tvmixer.c | 1 - drivers/media/video/v4l1-compat.c | 16 ----- drivers/media/video/v4l2-common.c | 18 ------ drivers/media/video/video-buf-dvb.c | 1 - drivers/media/video/video-buf.c | 1 - include/linux/videodev.h | 3 - include/linux/videodev2.h | 4 -- include/media/audiochip.h | 1 - include/media/id.h | 1 - include/media/ir-common.h | 4 +- include/media/tuner.h | 25 ++++---- include/media/tveeprom.h | 1 - include/media/video-buf.h | 1 - 27 files changed, 203 insertions(+), 154 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index f3302e1b1b9c4..f5876be658a64 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -64,3 +64,4 @@ tuner=62 - Philips TEA5767HN FM Radio tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner tuner=64 - LG TDVS-H062F/TUA6034 tuner=65 - Ymec TVF66T5-B/DFF +tuner=66 - LG NTSC (TALN mini series) diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c index ab7a1fba4427c..a0e700d7a4a4a 100644 --- a/drivers/media/common/ir-common.c +++ b/drivers/media/common/ir-common.c @@ -1,5 +1,4 @@ /* - * $Id: ir-common.c,v 1.11 2005/07/07 14:44:43 mchehab Exp $ * * some common structs and functions to handle infrared remotes via * input layer ... @@ -335,6 +334,72 @@ int ir_dump_samples(u32 *samples, int count) return 0; } +/* decode raw samples, pulse distance coding used by NEC remotes */ +int ir_decode_pulsedistance(u32 *samples, int count, int low, int high) +{ + int i,last,bit,len; + u32 curBit; + u32 value; + + /* find start burst */ + for (i = len = 0; i < count * 32; i++) { + bit = getbit(samples,i); + if (bit) { + len++; + } else { + if (len >= 29) + break; + len = 0; + } + } + + /* start burst to short */ + if (len < 29) + return 0xffffffff; + + /* find start silence */ + for (len = 0; i < count * 32; i++) { + bit = getbit(samples,i); + if (bit) { + break; + } else { + len++; + } + } + + /* silence to short */ + if (len < 7) + return 0xffffffff; + + /* go decoding */ + len = 0; + last = 1; + value = 0; curBit = 1; + for (; i < count * 32; i++) { + bit = getbit(samples,i); + if (last) { + if(bit) { + continue; + } else { + len = 1; + } + } else { + if (bit) { + if (len > (low + high) /2) + value |= curBit; + curBit <<= 1; + if (curBit == 1) + break; + } else { + len++; + } + } + last = bit; + } + + return value; +} + /* decode raw samples, biphase coding, used by rc5 for example */ int ir_decode_biphase(u32 *samples, int count, int low, int high) { @@ -383,6 +448,7 @@ EXPORT_SYMBOL_GPL(ir_input_keydown); EXPORT_SYMBOL_GPL(ir_extract_bits); EXPORT_SYMBOL_GPL(ir_dump_samples); EXPORT_SYMBOL_GPL(ir_decode_biphase); +EXPORT_SYMBOL_GPL(ir_decode_pulsedistance); /* * Local variables: diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c index 7f2d515d28737..a48de3c0e3f00 100644 --- a/drivers/media/video/btcx-risc.c +++ b/drivers/media/video/btcx-risc.c @@ -1,5 +1,4 @@ /* - $Id: btcx-risc.c,v 1.6 2005/02/21 13:57:59 kraxel Exp $ btcx-risc.c diff --git a/drivers/media/video/btcx-risc.h b/drivers/media/video/btcx-risc.h index 41f60395a5203..503e6c6d7b691 100644 --- a/drivers/media/video/btcx-risc.h +++ b/drivers/media/video/btcx-risc.h @@ -1,5 +1,4 @@ /* - * $Id: btcx-risc.h,v 1.2 2004/09/15 16:15:24 kraxel Exp $ */ struct btcx_riscmem { unsigned int size; diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c index a565823330aaa..eddadc76e11d6 100644 --- a/drivers/media/video/ir-kbd-gpio.c +++ b/drivers/media/video/ir-kbd-gpio.c @@ -1,5 +1,4 @@ /* - * $Id: ir-kbd-gpio.c,v 1.13 2005/05/15 19:01:26 mchehab Exp $ * * Copyright (c) 2003 Gerd Knorr * Copyright (c) 2003 Pavel Machek diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 1e273ff3f9568..67105b9804a23 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -1,5 +1,4 @@ /* - * $Id: ir-kbd-i2c.c,v 1.11 2005/07/07 16:42:11 mchehab Exp $ * * keyboard input driver for i2c IR remote controls * diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h index 023f33056a4f8..2d9ff40f0b09c 100644 --- a/drivers/media/video/msp3400.h +++ b/drivers/media/video/msp3400.h @@ -1,5 +1,4 @@ /* - * $Id: msp3400.h,v 1.3 2005/06/12 04:19:19 mchehab Exp $ */ #ifndef MSP3400_H diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 2fb7c2d1787a5..972aa5e0aeef6 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -1,5 +1,4 @@ /* - * $Id: mt20xx.c,v 1.5 2005/06/16 08:29:49 nsh Exp $ * * i2c tv tuner chip device driver * controls microtune tuners, mt2032 + mt2050 at the moment. @@ -494,6 +493,7 @@ int microtune_init(struct i2c_client *c) memset(buf,0,sizeof(buf)); t->tv_freq = NULL; t->radio_freq = NULL; + t->standby = NULL; name = "unknown"; i2c_master_send(c,buf,1); diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index a8b6a8df5109d..c65f0c7680a26 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -1,5 +1,4 @@ /* - * $Id: tda8290.c,v 1.15 2005/07/08 20:21:33 mchehab Exp $ * * i2c tv tuner chip device driver * controls the philips tda8290+75 tuner chip combo. @@ -9,6 +8,9 @@ #include <linux/delay.h> #include <media/tuner.h> +#define I2C_ADDR_TDA8290 0x4b +#define I2C_ADDR_TDA8275 0x61 + /* ---------------------------------------------------------------------- */ struct freq_entry { @@ -75,10 +77,12 @@ static unsigned char i2c_init_tda8275[14] = { 0x00, 0x00, 0x00, 0x00, static unsigned char i2c_set_VS[2] = { 0x30, 0x6F }; static unsigned char i2c_set_GP01_CF[2] = { 0x20, 0x0B }; static unsigned char i2c_tda8290_reset[2] = { 0x00, 0x00 }; +static unsigned char i2c_tda8290_standby[2] = { 0x00, 0x02 }; static unsigned char i2c_gainset_off[2] = { 0x28, 0x14 }; static unsigned char i2c_gainset_on[2] = { 0x28, 0x54 }; static unsigned char i2c_agc3_00[2] = { 0x80, 0x00 }; static unsigned char i2c_agc2_BF[2] = { 0x60, 0xBF }; +static unsigned char i2c_cb1_D0[2] = { 0x30, 0xD0 }; static unsigned char i2c_cb1_D2[2] = { 0x30, 0xD2 }; static unsigned char i2c_cb1_56[2] = { 0x30, 0x56 }; static unsigned char i2c_cb1_52[2] = { 0x30, 0x52 }; @@ -117,6 +121,13 @@ static struct i2c_msg i2c_msg_epilog[] = { { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_on), i2c_gainset_on }, }; +static struct i2c_msg i2c_msg_standby[] = { + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge }, + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D0), i2c_cb1_D0 }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_standby), i2c_tda8290_standby }, +}; + static int tda8290_tune(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); @@ -205,6 +216,11 @@ static int has_signal(struct i2c_client *c) return (afc & 0x80)? 65535:0; } +static void standby(struct i2c_client *c) +{ + i2c_transfer(c->adapter, i2c_msg_standby, ARRAY_SIZE(i2c_msg_standby)); +} + int tda8290_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); @@ -214,6 +230,7 @@ int tda8290_init(struct i2c_client *c) t->tv_freq = set_tv_freq; t->radio_freq = set_radio_freq; t->has_signal = has_signal; + t->standby = standby; i2c_master_send(c, i2c_enable_bridge, ARRAY_SIZE(i2c_enable_bridge)); i2c_transfer(c->adapter, i2c_msg_init, ARRAY_SIZE(i2c_msg_init)); diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index d60fc562aecdc..79e0bd1aa70f3 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -49,7 +49,7 @@ MODULE_LICENSE("GPL"); struct tda9887 { struct i2c_client client; v4l2_std_id std; - unsigned int radio; + enum tuner_mode mode; unsigned int config; unsigned int pinnacle_id; unsigned int using_v4l2; @@ -196,7 +196,7 @@ static struct tvnorm tvnorms[] = { .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), + cDeemphasis75 ), .e = ( cGating_36 | cAudioIF_4_5 | cVideoIF_45_75 ), @@ -364,7 +364,7 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) struct tvnorm *norm = NULL; int i; - if (t->radio) { + if (t->mode == T_RADIO) { if (t->radio_mode == V4L2_TUNER_MODE_MONO) norm = &radio_mono; else @@ -378,7 +378,7 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) } } if (NULL == norm) { - dprintk(PREFIX "Oops: no tvnorm entry found\n"); + dprintk(PREFIX "Unsupported tvnorm entry - audio muted\n"); return -1; } @@ -569,6 +569,10 @@ static int tda9887_configure(struct tda9887 *t) tda9887_set_config(t,buf); tda9887_set_insmod(t,buf); + if (t->mode == T_STANDBY) { + buf[1] |= cForcedMuteAudioON; + } + dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n", buf[1],buf[2],buf[3]); @@ -653,10 +657,17 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) /* --- configuration --- */ case AUDC_SET_RADIO: - t->radio = 1; + { + t->mode = T_RADIO; tda9887_configure(t); break; - + } + case TUNER_SET_STANDBY: + { + t->mode = T_STANDBY; + tda9887_configure(t); + break; + } case AUDC_CONFIG_PINNACLE: { int *i = arg; @@ -689,7 +700,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) struct video_channel *vc = arg; CHECK_V4L2; - t->radio = 0; + t->mode = T_ANALOG_TV; if (vc->norm < ARRAY_SIZE(map)) t->std = map[vc->norm]; tda9887_fixup_std(t); @@ -701,7 +712,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) v4l2_std_id *id = arg; SWITCH_V4L2; - t->radio = 0; + t->mode = T_ANALOG_TV; t->std = *id; tda9887_fixup_std(t); tda9887_configure(t); @@ -713,14 +724,14 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) SWITCH_V4L2; if (V4L2_TUNER_ANALOG_TV == f->type) { - if (t->radio == 0) + if (t->mode == T_ANALOG_TV) return 0; - t->radio = 0; + t->mode = T_ANALOG_TV; } if (V4L2_TUNER_RADIO == f->type) { - if (t->radio == 1) + if (t->mode == T_RADIO) return 0; - t->radio = 1; + t->mode = T_RADIO; } tda9887_configure(t); break; @@ -735,7 +746,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) }; struct v4l2_tuner* tuner = arg; - if (t->radio) { + if (t->mode == T_RADIO) { __u8 reg = 0; tuner->afc=0; if (1 == i2c_master_recv(&t->client,®,1)) @@ -747,7 +758,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct v4l2_tuner* tuner = arg; - if (t->radio) { + if (t->mode == T_RADIO) { t->radio_mode = tuner->audmode; tda9887_configure (t); } diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index cebcc1fa68d12..38bf50943798c 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -2,7 +2,6 @@ * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview * I2C address is allways 0xC0. * - * $Id: tea5767.c,v 1.27 2005/07/31 12:10:56 mchehab Exp $ * * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br) * This code is placed under the terms of the GNU General Public License @@ -205,11 +204,6 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq) TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; buffer[4] = 0; - if (t->mode == T_STANDBY) { - tuner_dbg("TEA5767 set to standby mode\n"); - buffer[3] |= TEA5767_STDBY; - } - if (t->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); buffer[2] |= TEA5767_MONO; @@ -290,13 +284,31 @@ static int tea5767_stereo(struct i2c_client *c) return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); } +static void tea5767_standby(struct i2c_client *c) +{ + unsigned char buffer[5]; + struct tuner *t = i2c_get_clientdata(c); + unsigned div, rc; + + div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; + buffer[2] = TEA5767_PORT1_HIGH; + buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | + TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; + buffer[4] = 0; + + if (5 != (rc = i2c_master_send(c, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); +} + int tea5767_autodetection(struct i2c_client *c) { unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int rc; struct tuner *t = i2c_get_clientdata(c); - if (7 != (rc = i2c_master_recv(c, buffer, 7))) { + if ((rc = i2c_master_recv(c, buffer, 7))< 5) { tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc); return EINVAL; } @@ -313,15 +325,10 @@ int tea5767_autodetection(struct i2c_client *c) * bit 0 : internally set to 0 * Byte 5: bit 7:0 : == 0 */ - if (!((buffer[3] & 0x0f) == 0x00) && (buffer[4] == 0x00)) { + if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { tuner_warn("Chip ID is not zero. It is not a TEA5767\n"); return EINVAL; } - /* It seems that tea5767 returns 0xff after the 5th byte */ - if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) { - tuner_warn("Returned more than 5 bytes. It is not a TEA5767\n"); - return EINVAL; - } /* It seems that tea5767 returns 0xff after the 5th byte */ if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) { @@ -337,14 +344,14 @@ int tea5767_tuner_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); - tuner_info("type set to %d (%s)\n", t->type, - "Philips TEA5767HN FM Radio"); + tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); strlcpy(c->name, "tea5767", sizeof(c->name)); t->tv_freq = set_tv_freq; t->radio_freq = set_radio_freq; t->has_signal = tea5767_signal; t->is_stereo = tea5767_stereo; + t->standby = tea5767_standby; return (0); } diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 3b1893c2ae3b1..afc96bbb1c118 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1,5 +1,4 @@ /* - * $Id: tuner-core.c,v 1.63 2005/07/28 18:19:55 mchehab Exp $ * * i2c tv tuner chip device driver * core core, i.e. kernel interfaces, registering and so on @@ -182,6 +181,14 @@ static void set_type(struct i2c_client *c, unsigned int type, i2c_master_send(c, buffer, 4); default_tuner_init(c); break; + case TUNER_LG_TDVS_H062F: + /* Set the Auxiliary Byte. */ + buffer[2] &= ~0x20; + buffer[2] |= 0x18; + buffer[3] = 0x20; + i2c_master_send(c, buffer, 4); + default_tuner_init(c); + break; default: default_tuner_init(c); break; @@ -208,31 +215,31 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) { struct tuner *t = i2c_get_clientdata(c); - if (tun_setup->addr == ADDR_UNSET) { - if (t->mode_mask & tun_setup->mode_mask) + if ((tun_setup->addr == ADDR_UNSET && + (t->mode_mask & tun_setup->mode_mask)) || + tun_setup->addr == c->addr) { set_type(c, tun_setup->type, tun_setup->mode_mask); - } else if (tun_setup->addr == c->addr) { - set_type(c, tun_setup->type, tun_setup->mode_mask); } } static inline int check_mode(struct tuner *t, char *cmd) { - if (1 << t->mode & t->mode_mask) { - switch (t->mode) { - case V4L2_TUNER_RADIO: - tuner_dbg("Cmd %s accepted for radio\n", cmd); - break; - case V4L2_TUNER_ANALOG_TV: - tuner_dbg("Cmd %s accepted for analog TV\n", cmd); - break; - case V4L2_TUNER_DIGITAL_TV: - tuner_dbg("Cmd %s accepted for digital TV\n", cmd); - break; - } - return 0; + if ((1 << t->mode & t->mode_mask) == 0) { + return EINVAL; + } + + switch (t->mode) { + case V4L2_TUNER_RADIO: + tuner_dbg("Cmd %s accepted for radio\n", cmd); + break; + case V4L2_TUNER_ANALOG_TV: + tuner_dbg("Cmd %s accepted for analog TV\n", cmd); + break; + case V4L2_TUNER_DIGITAL_TV: + tuner_dbg("Cmd %s accepted for digital TV\n", cmd); + break; } - return EINVAL; + return 0; } static char pal[] = "-"; @@ -406,20 +413,18 @@ static int tuner_detach(struct i2c_client *client) static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) { - if (mode != t->mode) { - - t->mode = mode; - if (check_mode(t, cmd) == EINVAL) { - t->mode = T_STANDBY; - if (V4L2_TUNER_RADIO == mode) { - set_tv_freq(client, 400 * 16); - } else { - set_radio_freq(client, 87.5 * 16000); - } - return EINVAL; - } - } - return 0; + if (mode == t->mode) + return 0; + + t->mode = mode; + + if (check_mode(t, cmd) == EINVAL) { + t->mode = T_STANDBY; + if (t->standby) + t->standby (client); + return EINVAL; + } + return 0; } #define switch_v4l2() if (!t->using_v4l2) \ @@ -453,6 +458,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) case AUDC_SET_RADIO: set_mode(client,t,V4L2_TUNER_RADIO, "AUDC_SET_RADIO"); break; + case TUNER_SET_STANDBY: + { + if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) + return 0; + if (t->standby) + t->standby (client); + break; + } case AUDC_CONFIG_PINNACLE: if (check_mode(t, "AUDC_CONFIG_PINNACLE") == EINVAL) return 0; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index de0c93aeb75d8..26034406b3721 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -1,5 +1,4 @@ /* - * $Id: tuner-simple.c,v 1.43 2005/07/28 18:41:21 mchehab Exp $ * * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. @@ -248,9 +247,10 @@ static struct tunertype tuners[] = { { "LG TDVS-H062F/TUA6034", LGINNOTEK, NTSC, 16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732}, - { "Ymec TVF66T5-B/DFF", Philips, PAL, 16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623}, + { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC, + 16*150.00,16*425.00,0x01,0x02,0x08,0x8e,732 }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); @@ -497,6 +497,7 @@ int default_tuner_init(struct i2c_client *c) t->radio_freq = default_set_radio_freq; t->has_signal = tuner_signal; t->is_stereo = tuner_stereo; + t->standby = NULL; return 0; } diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 3c3356a01cc67..d0a00d3a6c4f6 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -155,10 +155,10 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Philips FQ1216ME MK3"}, { TUNER_ABSENT, "Philips FI1236 MK3"}, { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, - { TUNER_ABSENT, "Philips FM1236 MK3"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, { TUNER_ABSENT, "Philips FM1216MP MK3"}, /* 60-69 */ - { TUNER_ABSENT, "LG S001D MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, { TUNER_ABSENT, "LG M001D MK3"}, { TUNER_ABSENT, "LG S701D MK3"}, { TUNER_ABSENT, "LG M701D MK3"}, @@ -183,8 +183,8 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Philips FQ1216LME MK3"}, { TUNER_ABSENT, "LG TAPC G701D"}, { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, - { TUNER_ABSENT, "TCL 2002MB 3"}, - { TUNER_ABSENT, "TCL 2002MI 3"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, { TUNER_TCL_2002N, "TCL 2002N 6A"}, { TUNER_ABSENT, "Philips FQ1236 MK3"}, { TUNER_ABSENT, "Samsung TCPN 2121P30A"}, @@ -445,23 +445,6 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) } EXPORT_SYMBOL(tveeprom_read); -#if 0 -int tveeprom_dump(unsigned char *eedata, int len) -{ - int i; - - dprintk(1, "%s\n",__FUNCTION__); - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "tveeprom: %02x:",i); - printk(" %02x",eedata[i]); - if (15 == (i % 16)) - printk("\n"); - } - return 0; -} -EXPORT_SYMBOL(tveeprom_dump); -#endif /* 0 */ /* ----------------------------------------------------------------------- */ /* needed for ivtv.sf.net at the moment. Should go away in the long */ diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index a43301a154af4..d86e08ebddfc2 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -1,5 +1,4 @@ /* - * $Id: tvmixer.c,v 1.8 2005/06/12 04:19:19 mchehab Exp $ */ #include <linux/module.h> diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index 70ecbdb80277f..59bb71381a1b1 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -1,5 +1,4 @@ /* - * $Id: v4l1-compat.c,v 1.9 2005/06/12 04:19:19 mchehab Exp $ * * Video for Linux Two * Backward Compatibility Layer @@ -604,9 +603,6 @@ v4l_compat_translate_ioctl(struct inode *inode, dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n",err); break; } -#if 0 /* FIXME */ - pict->depth = fmt2->fmt.pix.depth; -#endif pict->palette = pixelformat_to_palette( fmt2->fmt.pix.pixelformat); break; @@ -707,13 +703,7 @@ v4l_compat_translate_ioctl(struct inode *inode, } case VIDIOCSTUNER: /* select a tuner input */ { -#if 0 /* FIXME */ - err = drv(inode, file, VIDIOC_S_INPUT, &i); - if (err < 0) - dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n",err); -#else err = 0; -#endif break; } case VIDIOCGFREQ: /* get frequency */ @@ -852,12 +842,6 @@ v4l_compat_translate_ioctl(struct inode *inode, err = 0; break; } -#if 0 - case VIDIOCGMBUF: - /* v4l2 drivers must implement that themself. The - mmap() differences can't be translated fully - transparent, thus there is no point to try that */ -#endif case VIDIOCMCAPTURE: /* capture a frame */ { struct video_mmap *mm = arg; diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index b5e0cf3448f49..597b8db35a135 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -84,20 +84,6 @@ MODULE_LICENSE("GPL"); * Video Standard Operations (contributed by Michael Schimek) */ -#if 0 /* seems to have no users */ -/* This is the recommended method to deal with the framerate fields. More - sophisticated drivers will access the fields directly. */ -unsigned int -v4l2_video_std_fps(struct v4l2_standard *vs) -{ - if (vs->frameperiod.numerator > 0) - return (((vs->frameperiod.denominator << 8) / - vs->frameperiod.numerator) + - (1 << 7)) / (1 << 8); - return 0; -} -EXPORT_SYMBOL(v4l2_video_std_fps); -#endif /* Fill in the fields of a v4l2_standard structure according to the 'id' and 'transmission' parameters. Returns negative on error. */ @@ -213,10 +199,6 @@ char *v4l2_ioctl_names[256] = { [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", -#if 0 - [_IOC_NR(VIDIOC_G_COMP)] = "VIDIOC_G_COMP", - [_IOC_NR(VIDIOC_S_COMP)] = "VIDIOC_S_COMP", -#endif [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index 15f5bb4869638..55f129e964eb6 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -1,5 +1,4 @@ /* - * $Id: video-buf-dvb.c,v 1.7 2004/12/09 12:51:35 kraxel Exp $ * * some helper function for simple DVB cards which simply DMA the * complete transport stream and let the computer sort everything else diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index 5afdc78526103..97354f253a802 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -1,5 +1,4 @@ /* - * $Id: video-buf.c,v 1.18 2005/02/24 13:32:30 kraxel Exp $ * * generic helper functions for video4linux capture buffers, to handle * memory management and PCI DMA. Right now bttv + saa7134 use it. diff --git a/include/linux/videodev.h b/include/linux/videodev.h index 9d6fbde3d29cf..1cc8c31b79887 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -3,7 +3,6 @@ #include <linux/compiler.h> #include <linux/types.h> -#include <linux/version.h> #define HAVE_V4L2 1 #include <linux/videodev2.h> @@ -29,7 +28,6 @@ struct video_device void (*release)(struct video_device *vfd); -#if 1 /* to be removed in 2.7.x */ /* obsolete -- fops->owner is used instead */ struct module *owner; /* dev->driver_data will be used instead some day. @@ -37,7 +35,6 @@ struct video_device * so the switch over will be transparent for you. * Or use {pci|usb}_{get|set}_drvdata() directly. */ void *priv; -#endif /* for videodev.c intenal usage -- please don't touch */ int users; /* video_exclusive_{open|close} ... */ diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index acbfc525576df..f623a33b9abe8 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -270,7 +270,6 @@ struct v4l2_timecode /* The above is based on SMPTE timecodes */ -#if 1 /* * M P E G C O M P R E S S I O N P A R A M E T E R S * @@ -357,7 +356,6 @@ struct v4l2_mpeg_compression { /* I don't expect the above being perfect yet ;) */ __u32 reserved_5[8]; }; -#endif struct v4l2_jpegcompression { @@ -871,10 +869,8 @@ struct v4l2_streamparm #define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc) #define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format) #define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format) -#if 1 /* experimental */ #define VIDIOC_G_MPEGCOMP _IOR ('V', 6, struct v4l2_mpeg_compression) #define VIDIOC_S_MPEGCOMP _IOW ('V', 7, struct v4l2_mpeg_compression) -#endif #define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers) #define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer) #define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer) diff --git a/include/media/audiochip.h b/include/media/audiochip.h index cd831168fdc1d..a7ceee9fc5e9a 100644 --- a/include/media/audiochip.h +++ b/include/media/audiochip.h @@ -1,5 +1,4 @@ /* - * $Id: audiochip.h,v 1.5 2005/06/16 22:59:16 hhackmann Exp $ */ #ifndef AUDIOCHIP_H diff --git a/include/media/id.h b/include/media/id.h index 801ddef301aa3..6d02c94cdc0db 100644 --- a/include/media/id.h +++ b/include/media/id.h @@ -1,5 +1,4 @@ /* - * $Id: id.h,v 1.4 2005/06/12 04:19:19 mchehab Exp $ */ /* FIXME: this temporarely, until these are included in linux/i2c-id.h */ diff --git a/include/media/ir-common.h b/include/media/ir-common.h index 698670547f168..01b56822df4d9 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -1,5 +1,4 @@ /* - * $Id: ir-common.h,v 1.9 2005/05/15 19:01:26 mchehab Exp $ * * some common structs and functions to handle infrared remotes via * input layer ... @@ -21,11 +20,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <linux/version.h> #include <linux/input.h> #define IR_TYPE_RC5 1 +#define IR_TYPE_PD 2 /* Pulse distance encoded IR */ #define IR_TYPE_OTHER 99 #define IR_KEYTAB_TYPE u32 @@ -60,6 +59,7 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, u32 ir_extract_bits(u32 data, u32 mask); int ir_dump_samples(u32 *samples, int count); int ir_decode_biphase(u32 *samples, int count, int low, int high); +int ir_decode_pulsedistance(u32 *samples, int count, int low, int high); /* * Local variables: diff --git a/include/media/tuner.h b/include/media/tuner.h index eeaa15ddee851..252673bfa592f 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -1,5 +1,3 @@ - -/* $Id: tuner.h,v 1.45 2005/07/28 18:41:21 mchehab Exp $ * tuner.h - definition for different tuners @@ -111,6 +109,8 @@ #define TUNER_LG_TDVS_H062F 64 /* DViCO FusionHDTV 5 */ #define TUNER_YMEC_TVF66T5_B_DFF 65 /* Acorp Y878F */ +#define TUNER_LG_NTSC_TALN_MINI 66 + #define NOTUNER 0 #define PAL 1 /* PAL_BG */ #define PAL_I 2 @@ -134,6 +134,7 @@ #define THOMSON 12 #define TUNER_SET_TYPE_ADDR _IOW('T',3,int) +#define TUNER_SET_STANDBY _IOW('T',4,int) #define TDA9887_SET_CONFIG _IOW('t',5,int) /* tv card specific */ @@ -153,9 +154,6 @@ #ifdef __KERNEL__ -#define I2C_ADDR_TDA8290 0x4b -#define I2C_ADDR_TDA8275 0x61 - enum tuner_mode { T_UNINITIALIZED = 0, T_RADIO = 1 << V4L2_TUNER_RADIO, @@ -198,6 +196,7 @@ struct tuner { void (*radio_freq)(struct i2c_client *c, unsigned int freq); int (*has_signal)(struct i2c_client *c); int (*is_stereo)(struct i2c_client *c); + void (*standby)(struct i2c_client *c); }; extern unsigned int tuner_debug; @@ -209,12 +208,16 @@ extern int tea5767_tuner_init(struct i2c_client *c); extern int default_tuner_init(struct i2c_client *c); extern int tea5767_autodetection(struct i2c_client *c); -#define tuner_warn(fmt, arg...) \ - dev_printk(KERN_WARNING , &t->i2c.dev , fmt , ## arg) -#define tuner_info(fmt, arg...) \ - dev_printk(KERN_INFO , &t->i2c.dev , fmt , ## arg) -#define tuner_dbg(fmt, arg...) \ - if (tuner_debug) dev_printk(KERN_DEBUG , &t->i2c.dev , fmt , ## arg) +#define tuner_warn(fmt, arg...) do {\ + printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->name, \ + t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0) +#define tuner_info(fmt, arg...) do {\ + printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->name, \ + t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0) +#define tuner_dbg(fmt, arg...) do {\ + if (tuner_debug) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->name, \ + t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0) #endif /* __KERNEL__ */ diff --git a/include/media/tveeprom.h b/include/media/tveeprom.h index 854a2c2f105be..e24e841c32117 100644 --- a/include/media/tveeprom.h +++ b/include/media/tveeprom.h @@ -1,5 +1,4 @@ /* - * $Id: tveeprom.h,v 1.2 2005/06/12 04:19:19 mchehab Exp $ */ struct tveeprom { diff --git a/include/media/video-buf.h b/include/media/video-buf.h index ae6da6de98ded..ae8d7a0004402 100644 --- a/include/media/video-buf.h +++ b/include/media/video-buf.h @@ -1,5 +1,4 @@ /* - * $Id: video-buf.h,v 1.9 2004/11/07 13:17:15 kraxel Exp $ * * generic helper functions for video4linux capture buffers, to handle * memory management and PCI DMA. Right now bttv + saa7134 use it. -- GitLab From 24a70fdce872d70171b1f49dcd1a7c3a4e8396b2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:39 -0700 Subject: [PATCH 178/563] [PATCH] v4l: BTTV updates and card additions - Remove $Id CVS logs for V4L files - Added DVICO FusionHDTV 5 Lite card. - Added Acorp Y878F. - CodingStyle fixes. - Added tuner_addr to bttv cards structure. - linux/version.h replaced by linux/utsname.h on bttvp.h - kernel module for acquiring RDS data from a SAA6588. - Allow multiple open() and reading calls to /dev/radio on bttv-driver.c - added i2c address for lgdt330x. Signed-off-by: Hans J. Koch <koch@hjk-az.de> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/video4linux/CARDLIST.bttv | 2 + drivers/media/video/bttv-cards.c | 1175 +++++++++++++---------- drivers/media/video/bttv-driver.c | 48 +- drivers/media/video/bttv-gpio.c | 1 - drivers/media/video/bttv-i2c.c | 2 +- drivers/media/video/bttv-if.c | 1 - drivers/media/video/bttv-risc.c | 1 - drivers/media/video/bttv-vbi.c | 1 - drivers/media/video/bttv.h | 3 +- drivers/media/video/bttvp.h | 3 +- 10 files changed, 723 insertions(+), 514 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv index 62a12a08e2ac5..7979c060e787d 100644 --- a/Documentation/video4linux/CARDLIST.bttv +++ b/Documentation/video4linux/CARDLIST.bttv @@ -133,3 +133,5 @@ card=131 - Tibet Systems 'Progress DVR' CS16 card=132 - Kodicom 4400R (master) card=133 - Kodicom 4400R (slave) card=134 - Adlink RTV24 +card=135 - DVICO FusionHDTV 5 Lite +card=136 - Acorp Y878F diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index a97b9b958ed6d..3cb398b7a0285 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -1,5 +1,4 @@ /* - $Id: bttv-cards.c,v 1.54 2005/07/19 18:26:46 mkrufky Exp $ bttv-cards.c @@ -169,10 +168,10 @@ static struct CARD { { 0xd01810fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, { 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" }, - // some cards ship with byteswapped IDs ... + /* some cards ship with byteswapped IDs ... */ { 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" }, { 0xff00bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" }, - // this seems to happen as well ... + /* this seems to happen as well ... */ { 0xff1211bd, BTTV_PINNACLE, "Pinnacle PCTV" }, { 0x3000121a, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" }, @@ -200,12 +199,12 @@ static struct CARD { { 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV Radio+" }, { 0x1127153b, BTTV_TERRATV, "Terratec TV+ (V1.05)" }, - // clashes with FlyVideo - //{ 0x18521852, BTTV_TERRATV, "Terratec TV+ (V1.10)" }, + /* clashes with FlyVideo + *{ 0x18521852, BTTV_TERRATV, "Terratec TV+ (V1.10)" }, */ { 0x1134153b, BTTV_TERRATVALUE, "Terratec TValue (LR102)" }, - { 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, // LR102 - { 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" }, // ?? - { 0xff3b153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, // ?? + { 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, /* LR102 */ + { 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" }, /* ?? */ + { 0xff3b153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, /* ?? */ { 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, @@ -287,10 +286,12 @@ static struct CARD { { 0x01071805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" }, { 0x01081805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" }, - // likely broken, vendor id doesn't match the other magic views ... - //{ 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, + { 0x15409511, BTTV_ACORP_Y878F, "Acorp Y878F" }, - // DVB cards (using pci function .1 for mpeg data xfer) + /* likely broken, vendor id doesn't match the other magic views ... + * { 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ + + /* DVB cards (using pci function .1 for mpeg data xfer) */ { 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, { 0x07611461, BTTV_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, { 0x001c11bd, BTTV_PINNACLESAT, "Pinnacle PCTV Sat" }, @@ -299,6 +300,7 @@ static struct CARD { { 0xfc00270f, BTTV_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, { 0x07711461, BTTV_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, { 0xdb1018ac, BTTV_DVICO_DVBT_LITE, "DVICO FusionHDTV DVB-T Lite" }, + { 0xd50018ac, BTTV_DVICO_FUSIONHDTV_5_LITE, "DVICO FusionHDTV 5 Lite" }, { 0, -1, NULL } }; @@ -316,6 +318,7 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .muxsel = { 2, 3, 1, 0}, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "MIRO PCTV", .video_inputs = 4, @@ -327,6 +330,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 2, 0, 0, 0, 10}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Hauppauge (bt848)", .video_inputs = 4, @@ -338,6 +342,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 1, 2, 3, 4}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "STB, Gateway P/N 6000699 (bt848)", .video_inputs = 3, @@ -350,6 +355,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .needs_tvaudio = 1, .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, .has_radio = 1, },{ @@ -365,6 +371,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0 }, .needs_tvaudio = 0, .tuner_type = 4, + .tuner_addr = ADDR_UNSET, },{ .name = "Diamond DTV2000", .video_inputs = 4, @@ -376,6 +383,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 1, 0, 1, 3}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "AVerMedia TVPhone", .video_inputs = 3, @@ -388,6 +396,7 @@ struct tvcard bttv_tvcards[] = { /* 0x04 for some cards ?? */ .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .audio_hook = avermedia_tvphone_audio, .has_remote = 1, },{ @@ -401,6 +410,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = {0 }, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x08 ---------------------------------- */ @@ -415,6 +425,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "IMS/IXmicro TurboTV", .video_inputs = 3, @@ -427,6 +438,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, },{ .name = "Hauppauge (bt878)", .video_inputs = 4, @@ -439,6 +451,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "MIRO PCTV pro", .video_inputs = 3, @@ -450,6 +463,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0x20001,0x10001, 0, 0,10}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x0c ---------------------------------- */ @@ -463,6 +477,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 13, 14, 11, 7, 0, 0}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "AVerMedia TVCapture 98", .video_inputs = 3, @@ -476,6 +491,7 @@ struct tvcard bttv_tvcards[] = { .msp34xx_alt = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .audio_hook = avermedia_tv_stereo_audio, },{ .name = "Aimslab Video Highway Xtreme (VHX)", @@ -489,6 +505,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Zoltrix TV-Max", .video_inputs = 3, @@ -500,6 +517,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = {0 , 0, 1 , 0, 10}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x10 ---------------------------------- */ @@ -510,7 +528,7 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .gpiomask = 0x01fe00, .muxsel = { 2, 3, 1, 1}, - // 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> + /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */ .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 }, .needs_tvaudio = 1, .pll = PLL_28, @@ -526,6 +544,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .audio_hook = winview_audio, .has_radio = 1, },{ @@ -539,6 +558,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = {1, 0, 0, 0, 0}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)", .video_inputs = 4, @@ -550,6 +570,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0 }, .no_msp34xx = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x14 ---------------------------------- */ @@ -560,10 +581,11 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .muxsel = {2, 3, 1, 1}, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50", .video_inputs = 4, - .audio_inputs = 2, // tuner, line in + .audio_inputs = 2, /* tuner, line in */ .tuner = 0, .svhs = 2, .gpiomask = 0x1800, @@ -571,6 +593,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800}, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, },{ .name = "Askey CPH050/ Phoebe Tv Master + FM", .video_inputs = 3, @@ -583,6 +606,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878", .video_inputs = 3, @@ -591,11 +615,12 @@ struct tvcard bttv_tvcards[] = { .svhs = -1, .gpiomask = 7, .muxsel = { 2, 3, -1 }, - .digital_mode = DIGITAL_MODE_CAMERA, + .digital_mode = DIGITAL_MODE_CAMERA, .audiomux = { 0, 0, 0, 0, 0 }, .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_ALPS_TSBB5_PAL_I, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x18 ---------------------------------- */ @@ -610,6 +635,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .has_remote = 1, },{ .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar", @@ -622,6 +648,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000}, .needs_tvaudio = 0, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .audio_hook = terratv_audio, },{ .name = "Hauppauge WinCam newer (bt878)", @@ -634,6 +661,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 1, 2, 3, 4}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50", .video_inputs = 4, @@ -645,6 +673,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800}, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_SECAM, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x1c ---------------------------------- */ @@ -658,37 +687,38 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000}, .needs_tvaudio = 0, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .audio_hook = terratv_audio, /* GPIO wiring: - External 20 pin connector (for Active Radio Upgrade board) - gpio00: i2c-sda - gpio01: i2c-scl - gpio02: om5610-data - gpio03: om5610-clk - gpio04: om5610-wre - gpio05: om5610-stereo - gpio06: rds6588-davn - gpio07: Pin 7 n.c. - gpio08: nIOW - gpio09+10: nIOR, nSEL ?? (bt878) - gpio09: nIOR (bt848) - gpio10: nSEL (bt848) - Sound Routing: - gpio16: u2-A0 (1st 4052bt) - gpio17: u2-A1 - gpio18: u2-nEN - gpio19: u4-A0 (2nd 4052) - gpio20: u4-A1 - u4-nEN - GND - Btspy: - 00000 : Cdrom (internal audio input) + External 20 pin connector (for Active Radio Upgrade board) + gpio00: i2c-sda + gpio01: i2c-scl + gpio02: om5610-data + gpio03: om5610-clk + gpio04: om5610-wre + gpio05: om5610-stereo + gpio06: rds6588-davn + gpio07: Pin 7 n.c. + gpio08: nIOW + gpio09+10: nIOR, nSEL ?? (bt878) + gpio09: nIOR (bt848) + gpio10: nSEL (bt848) + Sound Routing: + gpio16: u2-A0 (1st 4052bt) + gpio17: u2-A1 + gpio18: u2-nEN + gpio19: u4-A0 (2nd 4052) + gpio20: u4-A1 + u4-nEN - GND + Btspy: + 00000 : Cdrom (internal audio input) 10000 : ext. Video audio input 20000 : TV Mono a0000 : TV Mono/2 - 1a0000 : TV Stereo + 1a0000 : TV Stereo 30000 : Radio 40000 : Mute - */ +*/ },{ /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */ @@ -702,6 +732,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0 }, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .muxsel_hook = PXC200_muxsel, },{ @@ -710,11 +741,12 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 1, .tuner = 0, .svhs = 2, - .gpiomask = 0x1800, //0x8dfe00 + .gpiomask = 0x1800, /* 0x8dfe00 */ .muxsel = { 2, 3, 1, 1}, .audiomux = { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 }, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Formac iProTV, Formac ProTV I (bt848)", .video_inputs = 4, @@ -726,6 +758,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 1, 0, 0, 0, 0 }, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x20 ---------------------------------- */ @@ -739,6 +772,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0 }, .needs_tvaudio = 0, .tuner_type = 4, + .tuner_addr = ADDR_UNSET, },{ .name = "Terratec TerraTValue Version Bt878", .video_inputs = 3, @@ -751,31 +785,33 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, },{ .name = "Leadtek WinFast 2000/ WinFast 2000 XP", .video_inputs = 4, .audio_inputs = 1, .tuner = 0, .svhs = 2, - .muxsel = { 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector + .muxsel = { 2, 3, 1, 1, 0}, /* TV, CVid, SVid, CVid over SVid connector */ /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */ .gpiomask = 0xb33000, .audiomux = { 0x122000,0x1000,0x0000,0x620000,0x800000 }, /* Audio Routing for "WinFast 2000 XP" (no tv stereo !) gpio23 -- hef4052:nEnable (0x800000) gpio12 -- hef4052:A1 - gpio13 -- hef4052:A0 - 0x0000: external audio - 0x1000: FM - 0x2000: TV - 0x3000: n.c. - Note: There exists another variant "Winfast 2000" with tv stereo !? - Note: eeprom only contains FF and pci subsystem id 107d:6606 - */ + gpio13 -- hef4052:A0 + 0x0000: external audio + 0x1000: FM + 0x2000: TV + 0x3000: n.c. + Note: There exists another variant "Winfast 2000" with tv stereo !? + Note: eeprom only contains FF and pci subsystem id 107d:6606 + */ .needs_tvaudio = 0, .pll = PLL_28, .has_radio = 1, - .tuner_type = 5, // default for now, gpio reads BFFF06 for Pal bg+dk + .tuner_type = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */ + .tuner_addr = ADDR_UNSET, .audio_hook = winfast2000_audio, .has_remote = 1, },{ @@ -789,6 +825,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800}, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x24 ---------------------------------- */ @@ -802,6 +839,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 }, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .has_radio = 1, },{ .name = "Prolink PixelView PlayTV pro", @@ -815,6 +853,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Askey CPH06X TView99", .video_inputs = 4, @@ -827,6 +866,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = 1, + .tuner_addr = ADDR_UNSET, .has_remote = 1, },{ .name = "Pinnacle PCTV Studio/Rave", @@ -840,6 +880,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x28 ---------------------------------- */ @@ -854,6 +895,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .needs_tvaudio = 1, .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, .has_radio = 1, },{ @@ -868,6 +910,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .has_radio = 1, .audio_hook = avermedia_tvphone_audio, },{ @@ -883,6 +926,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = 1, + .tuner_addr = ADDR_UNSET, },{ .name = "Little OnAir TV", .video_inputs = 3, @@ -894,6 +938,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc}, .no_msp34xx = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x2c ---------------------------------- */ @@ -908,6 +953,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_NONE, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "MATRIX-Vision MV-Delta 2", .video_inputs = 5, @@ -920,6 +966,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Zoltrix Genie TV/FM", .video_inputs = 3, @@ -932,6 +979,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = 21, + .tuner_addr = ADDR_UNSET, },{ .name = "Terratec TV/Radio+", .video_inputs = 3, @@ -945,6 +993,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_35, .tuner_type = 1, + .tuner_addr = ADDR_UNSET, .has_radio = 1, },{ @@ -960,6 +1009,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "IODATA GV-BCTV3/PCI", .video_inputs = 3, @@ -972,6 +1022,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_ALPS_TSHC6_NTSC, + .tuner_addr = ADDR_UNSET, .audio_hook = gvbctv3pci_audio, },{ .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP", @@ -986,6 +1037,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, .has_remote = 1, /* GPIO wiring: (different from Rev.4C !) GPIO17: U4.A0 (first hef4052bt) @@ -994,8 +1046,8 @@ struct tvcard bttv_tvcards[] = { GPIO21: U4.nEN GPIO22: BT832 Reset Line GPIO23: A5,A0, U5,nEN - Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22 - */ + Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22 + */ },{ .name = "Eagle Wireless Capricorn2 (bt878A)", .video_inputs = 4, @@ -1007,6 +1059,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 1, 2, 3, 4}, .pll = PLL_28, .tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x34 ---------------------------------- */ @@ -1020,20 +1073,21 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 3, 1, 1}, .audiomux = { 1, 0xd0001, 0, 0, 10}, /* sound path (5 sources): - MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable) + MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable) 0= ext. Audio IN 1= from MUX2 2= Mono TV sound from Tuner 3= not connected - MUX2 (mask 0x30000): + MUX2 (mask 0x30000): 0,2,3= from MSP34xx 1= FM stereo Radio from Tuner */ .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Claas Langbehn <claas@bigfoot.com>, - Sven Grothklags <sven@upb.de> */ + Sven Grothklags <sven@upb.de> */ .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS", .video_inputs = 4, .audio_inputs = 3, @@ -1045,10 +1099,11 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .has_radio = 1, },{ /* Tim R�stermundt <rosterm@uni-muenster.de> - in de.comp.os.unix.linux.hardware: + in de.comp.os.unix.linux.hardware: options bttv card=0 pll=1 radio=1 gpiomask=0x18e0 audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff options tuner type=5 */ @@ -1060,15 +1115,16 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x18e0, .muxsel = { 2, 3, 1, 1}, .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x18e0 }, - /* For cards with tda9820/tda9821: - 0x0000: Tuner normal stereo - 0x0080: Tuner A2 SAP (second audio program = Zweikanalton) - 0x0880: Tuner A2 stereo */ + /* For cards with tda9820/tda9821: + 0x0000: Tuner normal stereo + 0x0080: Tuner A2 SAP (second audio program = Zweikanalton) + 0x0880: Tuner A2 stereo */ .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Miguel Angel Alvarez <maacruz@navegalia.com> - old Easy TV BT848 version (model CPH031) */ + old Easy TV BT848 version (model CPH031) */ .name = "Askey CPH031/ BESTBUY Easy TV", .video_inputs = 4, .audio_inputs = 1, @@ -1080,6 +1136,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x38 ---------------------------------- */ @@ -1094,10 +1151,11 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 }, .pll = PLL_28, .tuner_type = 5, + .tuner_addr = ADDR_UNSET, },{ /* This is the ultimate cheapo capture card - * just a BT848A on a small PCB! - * Steve Hosgood <steve@equiinet.com> */ + * just a BT848A on a small PCB! + * Steve Hosgood <steve@equiinet.com> */ .name = "GrandTec 'Grand Video Capture' (Bt848)", .video_inputs = 2, .audio_inputs = 0, @@ -1110,19 +1168,21 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_35, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ - /* Daniel Herrington <daniel.herrington@home.com> */ - .name = "Askey CPH060/ Phoebe TV Master Only (No FM)", - .video_inputs = 3, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .gpiomask = 0xe00, - .muxsel = { 2, 3, 1, 1}, - .audiomux = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 }, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_4036FY5_NTSC, + /* Daniel Herrington <daniel.herrington@home.com> */ + .name = "Askey CPH060/ Phoebe TV Master Only (No FM)", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0xe00, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 }, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_4036FY5_NTSC, + .tuner_addr = ADDR_UNSET, },{ /* Matti Mottus <mottus@physic.ut.ee> */ .name = "Askey CPH03x TV Capturer", @@ -1130,11 +1190,12 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 1, .tuner = 0, .svhs = 2, - .gpiomask = 0x03000F, + .gpiomask = 0x03000F, .muxsel = { 2, 3, 1, 0}, - .audiomux = { 2,0,0,0,1 }, + .audiomux = { 2,0,0,0,1 }, .pll = PLL_28, .tuner_type = 0, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x3c ---------------------------------- */ @@ -1149,7 +1210,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 2, 0, 0, 1, 8}, .pll = PLL_35, .tuner_type = TUNER_TEMIC_PAL, - + .tuner_addr = ADDR_UNSET, },{ /* Adrian Cox <adrian@humboldt.co.uk */ .name = "AG Electronics GMV1", @@ -1164,10 +1225,11 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Miguel Angel Alvarez <maacruz@navegalia.com> - new Easy TV BT878 version (model CPH061) - special thanks to Informatica Mieres for providing the card */ + new Easy TV BT878 version (model CPH061) + special thanks to Informatica Mieres for providing the card */ .name = "Askey CPH061/ BESTBUY Easy TV (bt878)", .video_inputs = 3, .audio_inputs = 2, @@ -1179,6 +1241,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, },{ /* Lukas Gebauer <geby@volny.cz> */ .name = "ATI TV-Wonder", @@ -1191,6 +1254,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0xbffe, 0, 0xbfff, 0, 0xbffe}, .pll = PLL_28, .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x40 ---------------------------------- */ @@ -1206,6 +1270,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, + .tuner_addr = ADDR_UNSET, },{ /* DeeJay <deejay@westel900.net (2000S) */ .name = "Lifeview FlyVideo 2000S LR90", @@ -1216,7 +1281,7 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x18e0, .muxsel = { 2, 3, 0, 1}, /* Radio changed from 1e80 to 0x800 to make - FlyVideo2000S in .hu happy (gm)*/ + FlyVideo2000S in .hu happy (gm)*/ /* -dk-???: set mute=0x1800 for tda9874h daughterboard */ .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 }, .audio_hook = fv2000s_audio, @@ -1225,6 +1290,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = 5, + .tuner_addr = ADDR_UNSET, },{ .name = "Terratec TValueRadio", .video_inputs = 3, @@ -1237,6 +1303,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .has_radio = 1, },{ /* TANAKA Kei <peg00625@nifty.com> */ @@ -1251,25 +1318,27 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_SHARP_2U5JF5540_NTSC, + .tuner_addr = ADDR_UNSET, .audio_hook = gvbctv3pci_audio, },{ /* ---- card 0x44 ---------------------------------- */ - .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)", - // try "insmod msp3400 simple=0" if you have - // sound problems with this card. - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = -1, - .gpiomask = 0x4f8a00, - // 0x100000: 1=MSP enabled (0=disable again) - // 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) - .audiomux = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff}, - // tvtuner, radio, external,internal, mute, stereo - /* tuner, Composit, SVid, Composit-on-Svid-adapter*/ - .muxsel = { 2, 3 ,0 ,1}, - .tuner_type = TUNER_MT2032, + .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)", + /* try "insmod msp3400 simple=0" if you have + * sound problems with this card. */ + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = -1, + .gpiomask = 0x4f8a00, + /* 0x100000: 1=MSP enabled (0=disable again) + * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ + .audiomux = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff}, + /* tvtuner, radio, external,internal, mute, stereo + * tuner, Composit, SVid, Composit-on-Svid-adapter */ + .muxsel = { 2, 3 ,0 ,1}, + .tuner_type = TUNER_MT2032, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, .has_radio = 1, },{ @@ -1279,22 +1348,24 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 0, .tuner = -1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, .muxsel = { 2 }, .gpiomask = 0 },{ - /* Tomasz Pyra <hellfire@sedez.iq.pl> */ - .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)", - .video_inputs = 3, - .audio_inputs = 4, - .tuner = 0, - .svhs = 2, - .gpiomask = 15, - .muxsel = { 2, 3, 1, 1}, - .audiomux = { 0, 0, 11, 7, 13, 0}, // TV and Radio with same GPIO ! - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = 25, + /* Tomasz Pyra <hellfire@sedez.iq.pl> */ + .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)", + .video_inputs = 3, + .audio_inputs = 4, + .tuner = 0, + .svhs = 2, + .gpiomask = 15, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 0, 0, 11, 7, 13, 0}, /* TV and Radio with same GPIO ! */ + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = 25, + .tuner_addr = ADDR_UNSET, .has_remote = 1, /* GPIO wiring: GPIO0: U4.A0 (hef4052bt) @@ -1302,16 +1373,18 @@ struct tvcard bttv_tvcards[] = { GPIO2: U4.A1 (second hef4052bt) GPIO3: U4.nEN, U5.A0, A5.nEN GPIO8-15: vrd866b ? - */ + */ },{ .name = "Lifeview FlyVideo 98EZ (capture only) LR51", .video_inputs = 4, .audio_inputs = 0, .tuner = -1, .svhs = 2, - .muxsel = { 2, 3, 1, 1}, // AV1, AV2, SVHS, CVid adapter on SVHS + .muxsel = { 2, 3, 1, 1}, /* AV1, AV2, SVHS, CVid adapter on SVHS */ .pll = PLL_28, .no_msp34xx = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x48 ---------------------------------- */ @@ -1329,8 +1402,9 @@ struct tvcard bttv_tvcards[] = { .no_tda9875 = 1, .pll = PLL_28, .tuner_type = 5, - .audio_hook = pvbt878p9b_audio, // Note: not all cards have stereo - .has_radio = 1, // Note: not all cards have radio + .tuner_addr = ADDR_UNSET, + .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */ + .has_radio = 1, /* Note: not all cards have radio */ .has_remote = 1, /* GPIO wiring: GPIO0: A0 hef4052 @@ -1338,7 +1412,7 @@ struct tvcard bttv_tvcards[] = { GPIO3: nEN hef4052 GPIO8-15: vrd866b GPIO20,22,23: R30,R29,R28 - */ + */ },{ /* Clay Kunz <ckunz@mail.arc.nasa.gov> */ /* you must jumper JP5 for the card to work */ @@ -1352,6 +1426,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0 }, .needs_tvaudio = 0, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Miguel Freitas <miguel@cetuc.puc-rio.br> */ .name = "RemoteVision MX (RV605)", @@ -1362,71 +1437,78 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x00, .gpiomask2 = 0x07ff, .muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03, - 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 }, + 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 }, .no_msp34xx = 1, .no_tda9875 = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .muxsel_hook = rv605_muxsel, },{ - .name = "Powercolor MTV878/ MTV878R/ MTV878F", - .video_inputs = 3, - .audio_inputs = 2, + .name = "Powercolor MTV878/ MTV878R/ MTV878F", + .video_inputs = 3, + .audio_inputs = 2, .tuner = 0, - .svhs = 2, - .gpiomask = 0x1C800F, // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset - .muxsel = { 2, 1, 1, }, - .audiomux = { 0, 1, 2, 2, 4 }, - .needs_tvaudio = 0, - .tuner_type = TUNER_PHILIPS_PAL, + .svhs = 2, + .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */ + .muxsel = { 2, 1, 1, }, + .audiomux = { 0, 1, 2, 2, 4 }, + .needs_tvaudio = 0, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, .has_radio = 1, },{ /* ---- card 0x4c ---------------------------------- */ - /* Masaki Suzuki <masaki@btree.org> */ - .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)", - .video_inputs = 3, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .gpiomask = 0x140007, - .muxsel = { 2, 3, 1, 1 }, - .audiomux = { 0, 1, 2, 3, 4, 0 }, - .tuner_type = TUNER_PHILIPS_NTSC, - .audio_hook = windvr_audio, -},{ - .name = "GrandTec Multi Capture Card (Bt878)", - .video_inputs = 4, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .gpiomask = 0, - .muxsel = { 2, 3, 1, 0 }, - .audiomux = { 0 }, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = -1, -},{ - .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF", - .video_inputs = 4, - .audio_inputs = 3, - .tuner = 0, - .svhs = 2, - .gpiomask = 7, - .muxsel = { 2, 3, 1, 1 }, // Tuner, SVid, SVHS, SVid to SVHS connector - .audiomux = { 0 ,0 ,4, 4,4,4},// Yes, this tuner uses the same audio output for TV and FM radio! - // This card lacks external Audio In, so we mute it on Ext. & Int. - // The PCB can take a sbx1637/sbx1673, wiring unknown. - // This card lacks PCI subsystem ID, sigh. - // audiomux=1: lower volume, 2+3: mute - // btwincap uses 0x80000/0x80003 - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = 5, // Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and - // radio signal strength indicators work fine. - .has_radio = 1, + /* Masaki Suzuki <masaki@btree.org> */ + .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x140007, + .muxsel = { 2, 3, 1, 1 }, + .audiomux = { 0, 1, 2, 3, 4, 0 }, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .audio_hook = windvr_audio, +},{ + .name = "GrandTec Multi Capture Card (Bt878)", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .gpiomask = 0, + .muxsel = { 2, 3, 1, 0 }, + .audiomux = { 0 }, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, +},{ + .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF", + .video_inputs = 4, + .audio_inputs = 3, + .tuner = 0, + .svhs = 2, + .gpiomask = 7, + .muxsel = { 2, 3, 1, 1 }, /* Tuner, SVid, SVHS, SVid to SVHS connector */ + .audiomux = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio! + * This card lacks external Audio In, so we mute it on Ext. & Int. + * The PCB can take a sbx1637/sbx1673, wiring unknown. + * This card lacks PCI subsystem ID, sigh. + * audiomux=1: lower volume, 2+3: mute + * btwincap uses 0x80000/0x80003 + */ + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = 5, + .tuner_addr = ADDR_UNSET, + /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and + radio signal strength indicators work fine. */ + .has_radio = 1, /* GPIO Info: GPIO0,1: HEF4052 A0,A1 GPIO2: HEF4052 nENABLE @@ -1437,25 +1519,27 @@ struct tvcard bttv_tvcards[] = { GPIO22,23: ?? ?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/ },{ - /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */ - .name = "DSP Design TCVIDEO", - .video_inputs = 4, - .svhs = -1, - .muxsel = { 2, 3, 1, 0}, - .pll = PLL_28, - .tuner_type = -1, + /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */ + .name = "DSP Design TCVIDEO", + .video_inputs = 4, + .svhs = -1, + .muxsel = { 2, 3, 1, 0}, + .pll = PLL_28, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ - /* ---- card 0x50 ---------------------------------- */ + /* ---- card 0x50 ---------------------------------- */ .name = "Hauppauge WinTV PVR", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .muxsel = { 2, 0, 1, 1}, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = -1, + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .muxsel = { 2, 0, 1, 1}, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .gpiomask = 7, .audiomux = {7}, @@ -1471,6 +1555,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_NTSC_M, + .tuner_addr = ADDR_UNSET, .audio_hook = gvbctv5pci_audio, .has_radio = 1, },{ @@ -1482,9 +1567,10 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 3, 2, 0, 1 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */ .video_inputs = 3, @@ -1494,9 +1580,10 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 3, 1 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ /* ---- card 0x54 ---------------------------------- */ @@ -1508,9 +1595,10 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 3, 1 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */ .video_inputs = 1, @@ -1520,9 +1608,10 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 0 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */ .video_inputs = 2, @@ -1532,9 +1621,10 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 0, 1 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */ .video_inputs = 1, @@ -1543,10 +1633,11 @@ struct tvcard bttv_tvcards[] = { .svhs = -1, .muxsel = { 0 }, .pll = PLL_28, - .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ /* ---- card 0x58 ---------------------------------- */ @@ -1557,10 +1648,11 @@ struct tvcard bttv_tvcards[] = { .svhs = 1, .muxsel = { 0, 1 }, .pll = PLL_28, - .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */ .video_inputs = 2, @@ -1569,10 +1661,11 @@ struct tvcard bttv_tvcards[] = { .svhs = 1, .muxsel = { 2, 3 }, .pll = PLL_28, - .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 500", /* 500 */ .video_inputs = 2, @@ -1582,19 +1675,21 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 3 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ - .name = "Osprey 540", /* 540 */ - .video_inputs = 4, - .audio_inputs = 1, - .tuner = -1, - .pll = PLL_28, - .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .name = "Osprey 540", /* 540 */ + .video_inputs = 4, + .audio_inputs = 1, + .tuner = -1, + .pll = PLL_28, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ /* ---- card 0x5C ---------------------------------- */ @@ -1605,10 +1700,11 @@ struct tvcard bttv_tvcards[] = { .svhs = 1, .muxsel = { 2, 3 }, .pll = PLL_28, - .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */ + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */ },{ /* M G Berberich <berberic@forwiss.uni-passau.de> */ .name = "IDS Eagle", @@ -1616,6 +1712,7 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 0, .tuner = -1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .svhs = -1, .gpiomask = 0, .muxsel = { 0, 1, 2, 3 }, @@ -1630,6 +1727,7 @@ struct tvcard bttv_tvcards[] = { .svhs = 1, .tuner = -1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, .no_tda9875 = 1, .no_tda7432 = 1, @@ -1641,38 +1739,40 @@ struct tvcard bttv_tvcards[] = { .no_gpioirq = 1, .has_dvb = 1, },{ - .name = "Formac ProTV II (bt878)", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 3, - .gpiomask = 2, - // TV, Comp1, Composite over SVID con, SVID - .muxsel = { 2, 3, 1, 1}, - .audiomux = { 2, 2, 0, 0, 0 }, - .pll = PLL_28, + .name = "Formac ProTV II (bt878)", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 3, + .gpiomask = 2, + /* TV, Comp1, Composite over SVID con, SVID */ + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 2, 2, 0, 0, 0 }, + .pll = PLL_28, .has_radio = 1, - .tuner_type = TUNER_PHILIPS_PAL, - /* sound routing: - GPIO=0x00,0x01,0x03: mute (?) - 0x02: both TV and radio (tuner: FM1216/I) - The card has onboard audio connectors labeled "cdrom" and "board", - not soldered here, though unknown wiring. - Card lacks: external audio in, pci subsystem id. - */ + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, +/* sound routing: + GPIO=0x00,0x01,0x03: mute (?) + 0x02: both TV and radio (tuner: FM1216/I) + The card has onboard audio connectors labeled "cdrom" and "board", + not soldered here, though unknown wiring. + Card lacks: external audio in, pci subsystem id. +*/ },{ /* ---- card 0x60 ---------------------------------- */ .name = "MachTV", - .video_inputs = 3, - .audio_inputs = 1, - .tuner = 0, - .svhs = -1, - .gpiomask = 7, - .muxsel = { 2, 3, 1, 1}, - .audiomux = { 0, 1, 2, 3, 4}, - .needs_tvaudio = 1, - .tuner_type = 5, + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = -1, + .gpiomask = 7, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 0, 1, 2, 3, 4}, + .needs_tvaudio = 1, + .tuner_type = 5, + .tuner_addr = ADDR_UNSET, .pll = 1, },{ .name = "Euresys Picolo", @@ -1686,6 +1786,8 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .muxsel = { 2, 0, 1}, .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, },{ /* Luc Van Hoeylandt <luc@e-magic.be> */ .name = "ProVideo PV150", /* 0x4f */ @@ -1699,7 +1801,8 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, },{ /* Hiroshi Takekawa <sian@big.or.jp> */ /* This card lacks subsystem ID */ @@ -1716,78 +1819,85 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = 2, + .tuner_addr = ADDR_UNSET, .audio_hook = adtvk503_audio, },{ /* ---- card 0x64 ---------------------------------- */ - .name = "Hercules Smart TV Stereo", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .gpiomask = 0x00, - .muxsel = { 2, 3, 1, 1 }, - .needs_tvaudio = 1, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = 5, + .name = "Hercules Smart TV Stereo", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x00, + .muxsel = { 2, 3, 1, 1 }, + .needs_tvaudio = 1, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = 5, + .tuner_addr = ADDR_UNSET, /* Notes: - - card lacks subsystem ID - - stereo variant w/ daughter board with tda9874a @0xb0 - - Audio Routing: + - card lacks subsystem ID + - stereo variant w/ daughter board with tda9874a @0xb0 + - Audio Routing: always from tda9874 independent of GPIO (?) external line in: unknown - - Other chips: em78p156elp @ 0x96 (probably IR remote control) - hef4053 (instead 4052) for unknown function + - Other chips: em78p156elp @ 0x96 (probably IR remote control) + hef4053 (instead 4052) for unknown function */ },{ - .name = "Pace TV & Radio Card", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .muxsel = { 2, 3, 1, 1}, // Tuner, CVid, SVid, CVid over SVid connector - .gpiomask = 0, - .no_tda9875 = 1, - .no_tda7432 = 1, - .tuner_type = 1, - .has_radio = 1, - .pll = PLL_28, - /* Bt878, Bt832, FI1246 tuner; no pci subsystem id - only internal line out: (4pin header) RGGL - Radio must be decoded by msp3410d (not routed through)*/ - // .digital_mode = DIGITAL_MODE_CAMERA, // todo! -},{ - /* Chris Willing <chris@vislab.usyd.edu.au> */ - .name = "IVC-200", - .video_inputs = 1, - .audio_inputs = 0, - .tuner = -1, - .tuner_type = -1, - .svhs = -1, - .gpiomask = 0xdf, - .muxsel = { 2 }, - .pll = PLL_28, + .name = "Pace TV & Radio Card", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .muxsel = { 2, 3, 1, 1}, /* Tuner, CVid, SVid, CVid over SVid connector */ + .gpiomask = 0, + .no_tda9875 = 1, + .no_tda7432 = 1, + .tuner_type = 1, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + .pll = PLL_28, + /* Bt878, Bt832, FI1246 tuner; no pci subsystem id + only internal line out: (4pin header) RGGL + Radio must be decoded by msp3410d (not routed through)*/ + /* + .digital_mode = DIGITAL_MODE_CAMERA, todo! + */ +},{ + /* Chris Willing <chris@vislab.usyd.edu.au> */ + .name = "IVC-200", + .video_inputs = 1, + .audio_inputs = 0, + .tuner = -1, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .svhs = -1, + .gpiomask = 0xdf, + .muxsel = { 2 }, + .pll = PLL_28, },{ .name = "Grand X-Guard / Trust 814PCI", .video_inputs = 16, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, .tuner_type = 4, - .gpiomask2 = 0xff, + .tuner_addr = ADDR_UNSET, + .gpiomask2 = 0xff, .muxsel = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 }, .muxsel_hook = xguard_muxsel, .no_msp34xx = 1, .no_tda9875 = 1, - .no_tda7432 = 1, + .no_tda7432 = 1, .pll = PLL_28, },{ /* ---- card 0x68 ---------------------------------- */ .name = "Nebula Electronics DigiTV", .video_inputs = 1, - .tuner = -1, + .tuner = -1, .svhs = -1, .muxsel = { 2, 3, 1, 0}, .no_msp34xx = 1, @@ -1795,22 +1905,24 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .has_dvb = 1, .no_gpioirq = 1, },{ /* Jorge Boncompte - DTI2 <jorge@dti2.net> */ .name = "ProVideo PV143", - .video_inputs = 4, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .gpiomask = 0, - .muxsel = { 2, 3, 1, 0 }, - .audiomux = { 0 }, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = -1, + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .gpiomask = 0, + .muxsel = { 2, 3, 1, 0 }, + .audiomux = { 0 }, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* M.Klahr@phytec.de */ .name = "PHYTEC VD-009-X1 MiniDIN (bt878)", @@ -1824,6 +1936,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "PHYTEC VD-009-X1 Combi (bt878)", .video_inputs = 4, @@ -1836,6 +1949,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x6c ---------------------------------- */ @@ -1846,13 +1960,14 @@ struct tvcard bttv_tvcards[] = { .svhs = 9, .gpiomask = 0x00, .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio - via the upper nibble of muxsel. here: used for - xternal video-mux */ + via the upper nibble of muxsel. here: used for + xternal video-mux */ .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 }, .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */ .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "PHYTEC VD-009 Combi (bt878)", .video_inputs = 10, @@ -1861,23 +1976,25 @@ struct tvcard bttv_tvcards[] = { .svhs = 9, .gpiomask = 0x00, .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio - via the upper nibble of muxsel. here: used for - xternal video-mux */ + via the upper nibble of muxsel. here: used for + xternal video-mux */ .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 }, .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */ .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ - .name = "IVC-100", - .video_inputs = 4, - .audio_inputs = 0, - .tuner = -1, - .tuner_type = -1, - .svhs = -1, - .gpiomask = 0xdf, - .muxsel = { 2, 3, 1, 0 }, - .pll = PLL_28, + .name = "IVC-100", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .svhs = -1, + .gpiomask = 0xdf, + .muxsel = { 2, 3, 1, 0 }, + .pll = PLL_28, },{ /* IVC-120G - Alan Garfield <alan@fromorbit.com> */ .name = "IVC-120G", @@ -1885,6 +2002,7 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 0, /* card has no audio */ .tuner = -1, /* card has no tuner */ .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .svhs = -1, /* card has no svhs */ .needs_tvaudio = 0, .no_msp34xx = 1, @@ -1892,7 +2010,7 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .gpiomask = 0x00, .muxsel = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }, .muxsel_hook = ivc120_muxsel, .pll = PLL_28, },{ @@ -1905,6 +2023,7 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .muxsel = { 2, 3, 1, 0}, .tuner_type = TUNER_PHILIPS_ATSC, + .tuner_addr = ADDR_UNSET, .has_dvb = 1, },{ .name = "Twinhan DST + clones", @@ -1912,19 +2031,21 @@ struct tvcard bttv_tvcards[] = { .no_tda9875 = 1, .no_tda7432 = 1, .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, .no_video = 1, .has_dvb = 1, },{ - .name = "Winfast VC100", + .name = "Winfast VC100", .video_inputs = 3, .audio_inputs = 0, .svhs = 1, - .tuner = -1, // no tuner - .muxsel = { 3, 1, 1, 3}, // Vid In, SVid In, Vid over SVid in connector - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, + .tuner = -1, + .muxsel = { 3, 1, 1, 3}, /* Vid In, SVid In, Vid over SVid in connector */ + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, },{ .name = "Teppro TEV-560/InterVision IV-560", @@ -1937,44 +2058,49 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 1, 1, 1, 1, 0}, .needs_tvaudio = 1, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .pll = PLL_35, },{ /* ---- card 0x74 ---------------------------------- */ - .name = "SIMUS GVC1100", - .video_inputs = 4, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .tuner_type = -1, - .pll = PLL_28, - .muxsel = { 2, 2, 2, 2}, - .gpiomask = 0x3F, + .name = "SIMUS GVC1100", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .muxsel = { 2, 2, 2, 2}, + .gpiomask = 0x3F, .muxsel_hook = gvc1100_muxsel, },{ - /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */ - .name = "NGS NGSTV+", - .video_inputs = 3, - .tuner = 0, - .svhs = 2, - .gpiomask = 0x008007, - .muxsel = {2, 3, 0, 0}, - .audiomux = {0, 0, 0, 0, 0x000003, 0}, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .has_remote = 1, -},{ - /* http://linuxmedialabs.com */ - .name = "LMLBT4", - .video_inputs = 4, /* IN1,IN2,IN3,IN4 */ - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .muxsel = { 2, 3, 1, 0 }, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, - .needs_tvaudio = 0, + /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */ + .name = "NGS NGSTV+", + .video_inputs = 3, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x008007, + .muxsel = {2, 3, 0, 0}, + .audiomux = {0, 0, 0, 0, 0x000003, 0}, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, +},{ + /* http://linuxmedialabs.com */ + .name = "LMLBT4", + .video_inputs = 4, /* IN1,IN2,IN3,IN4 */ + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .muxsel = { 2, 3, 1, 0 }, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .needs_tvaudio = 0, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Helmroos Harri <harri.helmroos@pp.inet.fi> */ .name = "Tekram M205 PRO", @@ -1982,6 +2108,7 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 1, .tuner = 0, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .svhs = 2, .needs_tvaudio = 0, .gpiomask = 0x68, @@ -2004,6 +2131,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .has_remote = 1, .has_radio = 1, },{ @@ -2026,6 +2154,8 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .needs_tvaudio = 0, .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/ + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Spirit TV Tuner from http://spiritmodems.com.au */ /* Stafford Goodsell <surge@goliath.homeunix.org> */ @@ -2038,23 +2168,25 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 1, 1 }, .audiomux = { 0x02, 0x00, 0x00, 0x00, 0x00}, .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, .no_tda9875 = 1, },{ /* Wolfram Joost <wojo@frokaschwei.de> */ - .name = "AVerMedia AVerTV DVB-T 771", - .video_inputs = 2, - .svhs = 1, - .tuner = -1, - .tuner_type = TUNER_ABSENT, - .muxsel = { 3 , 3 }, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .has_dvb = 1, - .no_gpioirq = 1, - .has_remote = 1, + .name = "AVerMedia AVerTV DVB-T 771", + .video_inputs = 2, + .svhs = 1, + .tuner = -1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .muxsel = { 3 , 3 }, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .has_dvb = 1, + .no_gpioirq = 1, + .has_remote = 1, },{ /* ---- card 0x7c ---------------------------------- */ /* Matt Jesson <dvb@jesson.eclipse.co.uk> */ @@ -2069,6 +2201,7 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .has_dvb = 1, .no_gpioirq = 1, .has_remote = 1, @@ -2081,12 +2214,13 @@ struct tvcard bttv_tvcards[] = { .svhs = -1, .gpiomask = 0x0, .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3 }, + 3, 3, 3, 3, 3, 3, 3, 3 }, .muxsel_hook = sigmaSQ_muxsel, .audiomux = { 0 }, .no_msp34xx = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* andre.schwarz@matrix-vision.de */ .name = "MATRIX Vision Sigma-SLC", @@ -2101,6 +2235,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* BTTV_APAC_VIEWCOMP */ /* Attila Kondoros <attila.kondoros@chello.hu> */ @@ -2116,6 +2251,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */ .has_radio = 1, /* not every card has radio */ },{ @@ -2131,6 +2267,7 @@ struct tvcard bttv_tvcards[] = { .no_video = 1, .has_dvb = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Steven <photon38@pchome.com.tw> */ .name = "V-Gear MyVCD", @@ -2144,62 +2281,65 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_NTSC_M, + .tuner_addr = ADDR_UNSET, .has_radio = 0, - // .has_remote = 1, },{ /* Rick C <cryptdragoon@gmail.com> */ - .name = "Super TV Tuner", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .muxsel = { 2, 3, 1, 0}, - .tuner_type = TUNER_PHILIPS_NTSC, - .gpiomask = 0x008007, - .audiomux = { 0, 0x000001,0,0, 0}, - .needs_tvaudio = 1, - .has_radio = 1, -},{ - /* Chris Fanning <video4linux@haydon.net> */ - .name = "Tibet Systems 'Progress DVR' CS16", - .video_inputs = 16, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, - .tuner_type = -1, - .muxsel_hook = tibetCS16_muxsel, + .name = "Super TV Tuner", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .muxsel = { 2, 3, 1, 0}, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .gpiomask = 0x008007, + .audiomux = { 0, 0x000001,0,0, 0}, + .needs_tvaudio = 1, + .has_radio = 1, +},{ + /* Chris Fanning <video4linux@haydon.net> */ + .name = "Tibet Systems 'Progress DVR' CS16", + .video_inputs = 16, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .muxsel_hook = tibetCS16_muxsel, }, { /* Bill Brack <wbrack@mmm.com.hk> */ /* - * Note that, because of the card's wiring, the "master" - * BT878A chip (i.e. the one which controls the analog switch - * and must use this card type) is the 2nd one detected. The - * other 3 chips should use card type 0x85, whose description - * follows this one. There is a EEPROM on the card (which is - * connected to the I2C of one of those other chips), but is - * not currently handled. There is also a facility for a - * "monitor", which is also not currently implemented. - */ - .name = "Kodicom 4400R (master)", + * Note that, because of the card's wiring, the "master" + * BT878A chip (i.e. the one which controls the analog switch + * and must use this card type) is the 2nd one detected. The + * other 3 chips should use card type 0x85, whose description + * follows this one. There is a EEPROM on the card (which is + * connected to the I2C of one of those other chips), but is + * not currently handled. There is also a facility for a + * "monitor", which is also not currently implemented. + */ + .name = "Kodicom 4400R (master)", .video_inputs = 16, .audio_inputs = 0, .tuner = -1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .svhs = -1, /* GPIO bits 0-9 used for analog switch: - * 00 - 03: camera selector - * 04 - 06: channel (controller) selector - * 07: data (1->on, 0->off) - * 08: strobe - * 09: reset - * bit 16 is input from sync separator for the channel - */ + * 00 - 03: camera selector + * 04 - 06: channel (controller) selector + * 07: data (1->on, 0->off) + * 08: strobe + * 09: reset + * bit 16 is input from sync separator for the channel + */ .gpiomask = 0x0003ff, .no_gpioirq = 1, .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, @@ -2212,15 +2352,16 @@ struct tvcard bttv_tvcards[] = { { /* Bill Brack <wbrack@mmm.com.hk> */ /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the - * one which controls the analog switch, and must use the card type) - * is the 2nd one detected. The other 3 chips should use this card - * type - */ + * one which controls the analog switch, and must use the card type) + * is the 2nd one detected. The other 3 chips should use this card + * type + */ .name = "Kodicom 4400R (slave)", .video_inputs = 16, .audio_inputs = 0, .tuner = -1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .svhs = -1, .gpiomask = 0x010000, .no_gpioirq = 1, @@ -2232,18 +2373,51 @@ struct tvcard bttv_tvcards[] = { .muxsel_hook = kodicom4400r_muxsel, }, { - /* ---- card 0x85---------------------------------- */ - /* Michael Henson <mhenson@clarityvi.com> */ - /* Adlink RTV24 with special unlock codes */ - .name = "Adlink RTV24", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .muxsel = { 2, 3, 1, 0}, - .tuner_type = -1, - .pll = PLL_28, - + /* ---- card 0x86---------------------------------- */ + /* Michael Henson <mhenson@clarityvi.com> */ + /* Adlink RTV24 with special unlock codes */ + .name = "Adlink RTV24", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .muxsel = { 2, 3, 1, 0}, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, +}, +{ + /* ---- card 0x87---------------------------------- */ + /* Michael Krufky <mkrufky@m1k.net> */ + .name = "DVICO FusionHDTV 5 Lite", + .tuner = 0, + .tuner_type = TUNER_LG_TDVS_H062F, + .tuner_addr = ADDR_UNSET, + .video_inputs = 2, + .audio_inputs = 1, + .svhs = 2, + .muxsel = { 2, 3 }, + .gpiomask = 0x00e00007, + .audiomux = { 0x00400005, 0, 0, 0, 0, 0 }, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, +},{ + /* ---- card 0x88---------------------------------- */ + /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */ + .name = "Acorp Y878F", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x01fe00, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 }, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_YMEC_TVF66T5_B_DFF, + .tuner_addr = 0xc1 >>1, + .has_radio = 1, }}; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -2355,32 +2529,32 @@ static void flyvideo_gpio(struct bttv *btv) int tuner=-1,ttype; gpio_inout(0xffffff, 0); - udelay(8); // without this we would see the 0x1800 mask + udelay(8); /* without this we would see the 0x1800 mask */ gpio = gpio_read(); /* FIXME: must restore OUR_EN ??? */ - // all cards provide GPIO info, some have an additional eeprom - // LR50: GPIO coding can be found lower right CP1 .. CP9 - // CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1. - // GPIO14-12: n.c. - // LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878) - - // lowest 3 bytes are remote control codes (no handshake needed) - // xxxFFF: No remote control chip soldered - // xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered - // Note: Some bits are Audio_Mask ! + /* all cards provide GPIO info, some have an additional eeprom + * LR50: GPIO coding can be found lower right CP1 .. CP9 + * CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1. + * GPIO14-12: n.c. + * LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878) + * lowest 3 bytes are remote control codes (no handshake needed) + * xxxFFF: No remote control chip soldered + * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered + * Note: Some bits are Audio_Mask ! + */ ttype=(gpio&0x0f0000)>>16; switch(ttype) { - case 0x0: tuner=2; // NTSC, e.g. TPI8NSR11P + case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */ break; - case 0x2: tuner=39;// LG NTSC (newer TAPC series) TAPC-H701P + case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */ break; - case 0x4: tuner=5; // Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 + case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */ break; - case 0x6: tuner=37; // LG PAL (newer TAPC series) TAPC-G702P + case 0x6: tuner=37;/* LG PAL (newer TAPC series) TAPC-G702P */ break; - case 0xC: tuner=3; // Philips SECAM(+PAL) FQ1216ME or FI1216MF + case 0xC: tuner=3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ break; default: printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr); @@ -2388,15 +2562,16 @@ static void flyvideo_gpio(struct bttv *btv) has_remote = gpio & 0x800000; has_radio = gpio & 0x400000; - // unknown 0x200000; - // unknown2 0x100000; - is_capture_only = !(gpio & 0x008000); //GPIO15 + /* unknown 0x200000; + * unknown2 0x100000; */ + is_capture_only = !(gpio & 0x008000); /* GPIO15 */ has_tda9820_tda9821 = !(gpio & 0x004000); - is_lr90 = !(gpio & 0x002000); // else LR26/LR50 (LR38/LR51 f. capture only) - // gpio & 0x001000 // output bit for audio routing + is_lr90 = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */ + /* + * gpio & 0x001000 output bit for audio routing */ if(is_capture_only) - tuner=4; // No tuner present + tuner=4; /* No tuner present */ printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); @@ -2404,15 +2579,15 @@ static void flyvideo_gpio(struct bttv *btv) btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ", is_capture_only?"yes":"no "); - if(tuner!= -1) // only set if known tuner autodetected, else let insmod option through + if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */ btv->tuner_type = tuner; btv->has_radio = has_radio; - // LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 - // LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 - // Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute + /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 + * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 + * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio; - //todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; + /* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */ } static int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, @@ -2633,6 +2808,8 @@ void __devinit bttv_init_card1(struct bttv *btv) void __devinit bttv_init_card2(struct bttv *btv) { int tda9887; + int addr=ADDR_UNSET; + btv->tuner_type = -1; if (BTTV_UNKNOWN == btv->c.type) { @@ -2773,9 +2950,12 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->pll.pll_current = -1; /* tuner configuration (from card list / autodetect / insmod option) */ - if (UNSET != bttv_tvcards[btv->c.type].tuner_type) + if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr) + addr = bttv_tvcards[btv->c.type].tuner_addr; + + if (UNSET != bttv_tvcards[btv->c.type].tuner_type) if(UNSET == btv->tuner_type) - btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; + btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; if (UNSET != tuner[btv->c.nr]) btv->tuner_type = tuner[btv->c.nr]; printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type); @@ -2787,7 +2967,7 @@ void __devinit bttv_init_card2(struct bttv *btv) tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; tun_setup.type = btv->tuner_type; - tun_setup.addr = ADDR_UNSET; + tun_setup.addr = addr; bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup); } @@ -2902,7 +3082,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv) btv->mbox_csel = 1 << 10; freq=88000/62.5; - tea5757_write(btv, 5 * freq + 0x358); // write 0x1ed8 + tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */ if (0x1ed8 == tea5757_read(btv)) { printk("bttv%d: Terratec Active Radio Upgrade found.\n", btv->c.nr); @@ -3073,7 +3253,7 @@ static void __devinit osprey_eeprom(struct bttv *btv) case 0x0060: case 0x0070: btv->c.type = BTTV_OSPREY2x0; - //enable output on select control lines + /* enable output on select control lines */ gpio_inout(0xffffff,0x000303); break; default: @@ -3105,7 +3285,7 @@ static int tuner_1_table[] = { TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, - TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, //TUNER_TEMIC_SECAM + TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */ TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL}; static void __devinit avermedia_eeprom(struct bttv *btv) @@ -3126,7 +3306,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv) if (tuner_make == 4) if(tuner_format == 0x09) - tuner = TUNER_LG_NTSC_NEW_TAPC; // TAPC-G702P + tuner = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=", btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]); @@ -3143,7 +3323,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv) /* used on Voodoo TV/FM (Voodoo 200), S0 wired to 0x10000 */ void bttv_tda9880_setnorm(struct bttv *btv, int norm) { - // fix up our card entry + /* fix up our card entry */ if(norm==VIDEO_MODE_NTSC) { bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x957fff; bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x957fff; @@ -3154,7 +3334,7 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm) bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x947fff; dprintk("bttv_tda9880_setnorm to PAL\n"); } - // set GPIO according + /* set GPIO according */ gpio_bits(bttv_tvcards[btv->c.type].gpiomask, bttv_tvcards[btv->c.type].audiomux[btv->audio]); } @@ -3447,7 +3627,7 @@ static int tea5757_read(struct bttv *btv) udelay(10); timeout= jiffies + HZ; - // wait for DATA line to go low; error if it doesn't + /* wait for DATA line to go low; error if it doesn't */ while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) schedule(); if (bus_in(btv,btv->mbox_data)) { @@ -3574,8 +3754,8 @@ gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set) con = 0x300; if (v->mode & VIDEO_SOUND_STEREO) con = 0x200; -// if (v->mode & VIDEO_SOUND_MONO) -// con = 0x100; +/* if (v->mode & VIDEO_SOUND_MONO) + * con = 0x100; */ gpio_bits(0x300, con); } else { v->mode = VIDEO_SOUND_STEREO | @@ -3718,7 +3898,7 @@ lt9415_audio(struct bttv *btv, struct video_audio *v, int set) } } -// TDA9821 on TerraTV+ Bt848, Bt878 +/* TDA9821 on TerraTV+ Bt848, Bt878 */ static void terratv_audio(struct bttv *btv, struct video_audio *v, int set) { @@ -3818,7 +3998,7 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) } if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) || (v->mode & VIDEO_SOUND_STEREO)) { - val = 0x1080; //-dk-???: 0x0880, 0x0080, 0x1800 ... + val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ } if (val != 0xffff) { gpio_bits(0x1800, val); @@ -3869,10 +4049,10 @@ adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int con = 0xffffff; - //btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); + /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ if (set) { - //btor(***, BT848_GPIO_OUT_EN); + /* btor(***, BT848_GPIO_OUT_EN); */ if (v->mode & VIDEO_SOUND_LANG1) con = 0x00000000; if (v->mode & VIDEO_SOUND_LANG2) @@ -4079,14 +4259,14 @@ static void kodicom4400r_init(struct bttv *btv) master[btv->c.nr+2] = btv; } -// The Grandtec X-Guard framegrabber card uses two Dual 4-channel -// video multiplexers to provide up to 16 video inputs. These -// multiplexers are controlled by the lower 8 GPIO pins of the -// bt878. The multiplexers probably Pericom PI5V331Q or similar. - -// xxx0 is pin xxx of multiplexer U5, -// yyy1 is pin yyy of multiplexer U2 +/* The Grandtec X-Guard framegrabber card uses two Dual 4-channel + * video multiplexers to provide up to 16 video inputs. These + * multiplexers are controlled by the lower 8 GPIO pins of the + * bt878. The multiplexers probably Pericom PI5V331Q or similar. + * xxx0 is pin xxx of multiplexer U5, + * yyy1 is pin yyy of multiplexer U2 + */ #define ENA0 0x01 #define ENB0 0x02 #define ENA1 0x04 @@ -4157,14 +4337,14 @@ static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) static void ivc120_muxsel(struct bttv *btv, unsigned int input) { - // Simple maths + /* Simple maths */ int key = input % 4; int matrix = input / 4; dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", btv->c.nr, input, matrix, key); - // Handles the input selection on the TDA8540's + /* Handles the input selection on the TDA8540's */ bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00, ((matrix == 3) ? (key | key << 2) : 0x00), 1); bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00, @@ -4174,17 +4354,17 @@ static void ivc120_muxsel(struct bttv *btv, unsigned int input) bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00, ((matrix == 2) ? (key | key << 2) : 0x00), 1); - // Handles the output enables on the TDA8540's + /* Handles the output enables on the TDA8540's */ bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02, - ((matrix == 3) ? 0x03 : 0x00), 1); // 13 - 16 + ((matrix == 3) ? 0x03 : 0x00), 1); /* 13 - 16 */ bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02, - ((matrix == 0) ? 0x03 : 0x00), 1); // 1-4 + ((matrix == 0) ? 0x03 : 0x00), 1); /* 1-4 */ bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02, - ((matrix == 1) ? 0x03 : 0x00), 1); // 5-8 + ((matrix == 1) ? 0x03 : 0x00), 1); /* 5-8 */ bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02, - ((matrix == 2) ? 0x03 : 0x00), 1); // 9-12 + ((matrix == 2) ? 0x03 : 0x00), 1); /* 9-12 */ - // Selects MUX0 for input on the 878 + /* Selects MUX0 for input on the 878 */ btaor((0)<<5, ~(3<<5), BT848_IFORM); } @@ -4305,7 +4485,6 @@ void __devinit bttv_check_chipset(void) } if (UNSET != latency) printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency); - while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, dev))) { unsigned char b; diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 087efb4dea09a..53ecdbf462226 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -1,5 +1,4 @@ /* - $Id: bttv-driver.c,v 1.52 2005/08/04 00:55:16 mchehab Exp $ bttv - Bt848 frame grabber driver @@ -42,6 +41,9 @@ #include "bttvp.h" +#include "rds.h" + + unsigned int bttv_num; /* number of Bt848s in use */ struct bttv bttvs[BTTV_MAX]; @@ -3128,15 +3130,12 @@ static int radio_open(struct inode *inode, struct file *file) dprintk("bttv%d: open called (radio)\n",btv->c.nr); down(&btv->lock); - if (btv->radio_user) { - up(&btv->lock); - return -EBUSY; - } + btv->radio_user++; + file->private_data = btv; - i2c_vidiocschan(btv); - bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type); + bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type); audio_mux(btv,AUDIO_RADIO); up(&btv->lock); @@ -3145,9 +3144,13 @@ static int radio_open(struct inode *inode, struct file *file) static int radio_release(struct inode *inode, struct file *file) { - struct bttv *btv = file->private_data; + struct bttv *btv = file->private_data; + struct rds_command cmd; btv->radio_user--; + + bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd); + return 0; } @@ -3203,13 +3206,42 @@ static int radio_ioctl(struct inode *inode, struct file *file, return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); } +static ssize_t radio_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct bttv *btv = file->private_data; + struct rds_command cmd; + cmd.block_count = count/3; + cmd.buffer = data; + cmd.instance = file; + cmd.result = -ENODEV; + + bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd); + + return cmd.result; +} + +static unsigned int radio_poll(struct file *file, poll_table *wait) +{ + struct bttv *btv = file->private_data; + struct rds_command cmd; + cmd.instance = file; + cmd.event_list = wait; + cmd.result = -ENODEV; + bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd); + + return cmd.result; +} + static struct file_operations radio_fops = { .owner = THIS_MODULE, .open = radio_open, + .read = radio_read, .release = radio_release, .ioctl = radio_ioctl, .llseek = no_llseek, + .poll = radio_poll, }; static struct video_device radio_template = diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c index 77320cdf205fc..6b280c03e398d 100644 --- a/drivers/media/video/bttv-gpio.c +++ b/drivers/media/video/bttv-gpio.c @@ -1,5 +1,4 @@ /* - $Id: bttv-gpio.c,v 1.7 2005/02/16 12:14:10 kraxel Exp $ bttv-gpio.c -- gpio sub drivers diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index 706dc48df9625..e684df37eb0e2 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -1,5 +1,4 @@ /* - $Id: bttv-i2c.c,v 1.25 2005/07/05 17:37:35 nsh Exp $ bttv-i2c.c -- all the i2c code is here @@ -381,6 +380,7 @@ void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) } static char *i2c_devs[128] = { + [ 0x1c >> 1 ] = "lgdt330x", [ 0x30 >> 1 ] = "IR (hauppauge)", [ 0x80 >> 1 ] = "msp34xx", [ 0x86 >> 1 ] = "tda9887", diff --git a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c index f7b5543a96a1b..e8aada772b89b 100644 --- a/drivers/media/video/bttv-if.c +++ b/drivers/media/video/bttv-if.c @@ -1,5 +1,4 @@ /* - $Id: bttv-if.c,v 1.4 2004/11/17 18:47:47 kraxel Exp $ bttv-if.c -- old gpio interface to other kernel modules don't use in new code, will go away in 2.7 diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c index 9ed21fd190c6c..a5ed99b894451 100644 --- a/drivers/media/video/bttv-risc.c +++ b/drivers/media/video/bttv-risc.c @@ -1,5 +1,4 @@ /* - $Id: bttv-risc.c,v 1.10 2004/11/19 18:07:12 kraxel Exp $ bttv-risc.c -- interfaces to other kernel modules diff --git a/drivers/media/video/bttv-vbi.c b/drivers/media/video/bttv-vbi.c index 06f3e62b3e8d0..f4f58c60f152b 100644 --- a/drivers/media/video/bttv-vbi.c +++ b/drivers/media/video/bttv-vbi.c @@ -1,5 +1,4 @@ /* - $Id: bttv-vbi.c,v 1.9 2005/01/13 17:22:33 kraxel Exp $ bttv - Bt848 frame grabber driver vbi interface diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h index f2af9e1454f08..d254e90e3bb9f 100644 --- a/drivers/media/video/bttv.h +++ b/drivers/media/video/bttv.h @@ -1,5 +1,4 @@ /* - * $Id: bttv.h,v 1.22 2005/07/28 18:41:21 mchehab Exp $ * * bttv - Bt848 frame grabber driver * @@ -218,6 +217,8 @@ struct tvcard #define PLL_35 2 unsigned int tuner_type; + unsigned int tuner_addr; + unsigned int has_radio; void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); void (*muxsel_hook)(struct bttv *btv, unsigned int input); diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index aab094bc243dd..a0eb0ce1aa96b 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -1,5 +1,4 @@ /* - $Id: bttvp.h,v 1.21 2005/07/15 21:44:14 mchehab Exp $ bttv - Bt848 frame grabber driver @@ -26,7 +25,7 @@ #ifndef _BTTVP_H_ #define _BTTVP_H_ -#include <linux/version.h> +#include <linux/utsname.h> #define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16) #include <linux/types.h> -- GitLab From e52e98a7eccfb0e7e91630d01690fb11d77db77d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:41 -0700 Subject: [PATCH 179/563] [PATCH] v4l: CX88 updates and card additions - Remove $Id CVS logs for V4L files - add ioctl indirection via cx88_ioctl_hook and cx88_ioctl_translator to cx88-blackbird.c. - declare the indirection hooks from cx88-blackbird.c. - dcprintk macro which uses core instead of dev->core on cx88-video.c. - replace dev->core occurances with core on cx88-video.c. - CodingStyle fixes. - MaxInput replaced by a define. - cx8801 structures moved from cx88.h. - The output_mode needs to be set for the Hauppauge Nova-T DVB-T for versions after 2.6.12. - Corrected GPIO values for cx88 cards #28 & #31 for s-video and composite. - Updated DViCO FusionHDTV5 Gold & added DVB support. - Fixed DViCO FusionHDTV 3 Gold-Q GPIO. - Some clean up in cx88-tvaudio.c - replaced hex values when writing to AUD_CTL to EN_xx for better reading. - Allow select by hand between Mono, Lang1, Lang2 and Stereo for BTSC. - Support for stereo NICAM and BTSC improved. - Broken stereo check removed. - Added support for remote control to Cinergy DVBT-1400. - local var renamed from rc5 to a better name (ircode). - LGDT330X QAM lock bug fixes. - Some reorg: move some bits to struct cx88_core, factor out common ioctl's to cx88_do_ioctl. - Get rid of '//' comments, replace them with #if 0 and /**/. - Minor clean-ups: remove dcprintk and replace all instances of "dev->core" with "core". - Added some registers to control PCI controller at CX2388x chips. - New tuner standby API. - Small mpeg fixes and cleanups for blackbird. - fix mpeg packet size & count - add VIDIOC_QUERYCAP ioctl for the mpeg stream - return more information in struct v4l2_format - fix default window height - small cleanups Signed-off-by: Uli Luckas <luckas@musoft.de> Signed-off-by: Torsten Seeboth <Torsten.Seeboth@t-online.de> Signed-off-by: Nickolay V. Shmyrev <nshmyrev@yandex.ru> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Patrick Boettcher <patrick.boettcher@desy.de> Signed-off-by: Catalin Climov <catalin@climov.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/cx88/cx88-blackbird.c | 73 ++- drivers/media/video/cx88/cx88-cards.c | 24 +- drivers/media/video/cx88/cx88-core.c | 21 +- drivers/media/video/cx88/cx88-dvb.c | 47 +- drivers/media/video/cx88/cx88-i2c.c | 1 - drivers/media/video/cx88/cx88-input.c | 96 ++- drivers/media/video/cx88/cx88-mpeg.c | 17 +- drivers/media/video/cx88/cx88-reg.h | 24 +- drivers/media/video/cx88/cx88-tvaudio.c | 742 +++++++++++----------- drivers/media/video/cx88/cx88-vbi.c | 1 - drivers/media/video/cx88/cx88-video.c | 388 ++++++----- drivers/media/video/cx88/cx88.h | 39 +- 12 files changed, 874 insertions(+), 599 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 4f39688f780a2..0c0c59e947749 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-blackbird.c,v 1.27 2005/06/03 13:31:50 mchehab Exp $ * * Support for a cx23416 mpeg encoder via cx2388x host port. * "blackbird" reference design. @@ -62,7 +61,6 @@ static LIST_HEAD(cx8802_devlist); #define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF /* Firmware API commands */ -/* #define IVTV_API_STD_TIMEOUT 0x00010000 // 65536, units?? */ #define IVTV_API_STD_TIMEOUT 500 #define BLACKBIRD_API_PING 0x80 @@ -696,7 +694,6 @@ static void blackbird_codec_settings(struct cx8802_dev *dev) /* assign stream type */ blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_PROGRAM); - /* blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_TRANSPORT); */ /* assign output port */ blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */ @@ -824,7 +821,8 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0); /* initialize the video input */ + /* initialize the video input */ + blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0); msleep(1); @@ -833,11 +831,12 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE); msleep(1); - /* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); // start capturing to the host interface */ + /* start capturing to the host interface */ + /* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); */ blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE - ); /* start capturing to the host interface */ + ); msleep(10); blackbird_api_cmd(dev, BLACKBIRD_API_REFRESH_INPUT, 0,0); @@ -851,8 +850,8 @@ static int bb_buf_setup(struct videobuf_queue *q, { struct cx8802_fh *fh = q->priv_data; - fh->dev->ts_packet_size = 512; - fh->dev->ts_packet_count = 100; + fh->dev->ts_packet_size = 188 * 4; /* was: 512 */ + fh->dev->ts_packet_count = 32; /* was: 100 */ *size = fh->dev->ts_packet_size * fh->dev->ts_packet_count; if (0 == *count) @@ -900,12 +899,36 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, { struct cx8802_fh *fh = file->private_data; struct cx8802_dev *dev = fh->dev; + struct cx88_core *core = dev->core; if (debug > 1) - cx88_print_ioctl(dev->core->name,cmd); + cx88_print_ioctl(core->name,cmd); switch (cmd) { + /* --- capabilities ------------------------------------------ */ + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + + memset(cap,0,sizeof(*cap)); + strcpy(cap->driver, "cx88_blackbird"); + strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); + cap->version = CX88_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_VIDEO_OVERLAY | + 0; + if (UNSET != core->tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; + + return 0; + } + /* --- capture ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: { @@ -935,7 +958,11 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = 1024 * 512 /* FIXME: BUFFER_SIZE */; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = 188 * 4 * 1024; /* 1024 * 512 */ /* FIXME: BUFFER_SIZE */; + f->fmt.pix.colorspace = 0; + return 0; } /* --- streaming capture ------------------------------------- */ @@ -959,15 +986,25 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, return videobuf_streamoff(&fh->mpegq); default: - return -EINVAL; + return cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook ); } return 0; } +int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +unsigned int (*cx88_ioctl_translator)(unsigned int cmd); + +static unsigned int mpeg_translate_ioctl(unsigned int cmd) +{ + return cmd; +} + static int mpeg_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl); + cmd = cx88_ioctl_translator( cmd ); + return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook); } static int mpeg_open(struct inode *inode, struct file *file) @@ -1135,7 +1172,7 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev, dev->pci = pci_dev; dev->core = core; dev->width = 720; - dev->height = 480; + dev->height = 576; err = cx8802_init_common(dev); if (0 != err) @@ -1148,6 +1185,9 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev, list_add_tail(&dev->devlist,&cx8802_devlist); blackbird_register_video(dev); + + /* initial device configuration: needed ? */ + return 0; fail_free: @@ -1202,6 +1242,8 @@ static int blackbird_init(void) printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif + cx88_ioctl_hook = mpeg_do_ioctl; + cx88_ioctl_translator = mpeg_translate_ioctl; return pci_register_driver(&blackbird_pci_driver); } @@ -1213,6 +1255,9 @@ static void blackbird_fini(void) module_init(blackbird_init); module_exit(blackbird_fini); +EXPORT_SYMBOL(cx88_ioctl_hook); +EXPORT_SYMBOL(cx88_ioctl_translator); + /* ----------------------------------------------------------- */ /* * Local variables: diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index ebf02a7f81e80..92623231db78c 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-cards.c,v 1.90 2005/07/28 02:47:42 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * card-specific stuff. @@ -499,9 +498,6 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_DVB, .vmux = 0, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, }}, .dvb = 1, }, @@ -614,12 +610,12 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0xed12, // internal decoder + .gpio0 = 0xed12, /* internal decoder */ .gpio2 = 0x00ff, },{ .type = CX88_VMUX_DEBUG, .vmux = 0, - .gpio0 = 0xff01, // mono from tuner chip + .gpio0 = 0xff01, /* mono from tuner chip */ },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, @@ -715,19 +711,18 @@ struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - /* See DViCO FusionHDTV 3 Gold-Q for GPIO documentation. */ .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0x0f0d, + .gpio0 = 0x97ed, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - .gpio0 = 0x0f00, + .gpio0 = 0x97e9, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, - .gpio0 = 0x0f00, + .gpio0 = 0x97e9, }}, .dvb = 1, }, @@ -765,20 +760,21 @@ struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - /* See DViCO FusionHDTV 3 Gold-Q for GPIO documentation. */ + .tda9887_conf = TDA9887_PRESENT, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0x0f0d, + .gpio0 = 0x87fd, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - .gpio0 = 0x0f00, + .gpio0 = 0x87f9, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, - .gpio0 = 0x0f00, + .gpio0 = 0x87f9, }}, + .dvb = 1, }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 5e868f5cd0c0b..dc5c5c1f34611 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-core.c,v 1.33 2005/07/07 14:17:47 mchehab Exp $ * * device driver for Conexant 2388x based TV cards * driver core @@ -876,7 +875,7 @@ static int set_tvaudio(struct cx88_core *core) cx_andor(MO_AFECFG_IO, 0x1f, 0x0); cx88_set_tvaudio(core); - // cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); + /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */ cx_write(MO_AUDD_LNGTH, 128); /* fifo size */ cx_write(MO_AUDR_LNGTH, 128); /* fifo size */ @@ -1087,10 +1086,17 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); core->pci_irqmask = 0x00fc00; + init_MUTEX(&core->lock); core->nr = cx88_devcount++; sprintf(core->name,"cx88[%d]",core->nr); if (0 != get_ressources(core,pci)) { + printk(KERN_ERR "CORE %s No more PCI ressources for " + "subsystem: %04x:%04x, board: %s\n", + core->name,pci->subsystem_vendor, + pci->subsystem_device, + cx88_boards[core->board].name); + cx88_devcount--; goto fail_free; } @@ -1114,11 +1120,11 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->board = CX88_BOARD_UNKNOWN; cx88_card_list(core,pci); } - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - core->name,pci->subsystem_vendor, - pci->subsystem_device,cx88_boards[core->board].name, - core->board, card[core->nr] == core->board ? - "insmod option" : "autodetected"); + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + core->name,pci->subsystem_vendor, + pci->subsystem_device,cx88_boards[core->board].name, + core->board, card[core->nr] == core->board ? + "insmod option" : "autodetected"); core->tuner_type = tuner[core->nr]; core->radio_type = radio[core->nr]; @@ -1202,4 +1208,5 @@ EXPORT_SYMBOL(cx88_core_put); * Local variables: * c-basic-offset: 8 * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off */ diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 78d223257a688..cc71cafc2cbd9 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-dvb.c,v 1.58 2005/08/07 09:24:08 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines @@ -31,6 +30,7 @@ #include <linux/suspend.h> #include <linux/config.h> + #include "cx88.h" #include "dvb-pll.h" @@ -210,16 +210,26 @@ static struct or51132_config pchdtv_hd3000 = { static int lgdt330x_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { + /* FIXME make this routine use the tuner-simple code. + * It could probably be shared with a number of ATSC + * frontends. Many share the same tuner with analog TV. */ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx88_core *core = dev->core; u8 buf[4]; struct i2c_msg msg = { .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 }; int err; - dvb_pll_configure(dev->core->pll_desc, buf, params->frequency, 0); + /* Put the analog decoder in standby to keep it quiet */ + if (core->tda9887_conf) { + cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); + } + + dvb_pll_configure(core->pll_desc, buf, params->frequency, 0); dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n", __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]); - if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) { + if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) { printk(KERN_WARNING "cx88-dvb: %s error " "(addr %02x <- %02x, err = %i)\n", __FUNCTION__, buf[0], buf[1], err); @@ -228,6 +238,13 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe, else return -EREMOTEIO; } + if (core->tuner_type == TUNER_LG_TDVS_H062F) { + /* Set the Auxiliary Byte. */ + buf[2] &= ~0x20; + buf[2] |= 0x18; + buf[3] = 0x50; + i2c_transfer(&core->i2c_adap, &msg, 1); + } return 0; } @@ -261,6 +278,14 @@ static struct lgdt330x_config fusionhdtv_3_gold = { .pll_set = lgdt330x_pll_set, .set_ts_params = lgdt330x_set_ts_param, }; + +static struct lgdt330x_config fusionhdtv_5_gold = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ + .pll_set = lgdt330x_pll_set, + .set_ts_params = lgdt330x_set_ts_param, +}; #endif static int dvb_register(struct cx8802_dev *dev) @@ -346,6 +371,22 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); } break; + case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: + dev->ts_gen_cntrl = 0x08; + { + /* Do a hardware reset of chip before using it. */ + struct cx88_core *core = dev->core; + + cx_clear(MO_GP0_IO, 1); + mdelay(100); + cx_set(MO_GP0_IO, 1); + mdelay(200); + dev->core->pll_addr = 0x61; + dev->core->pll_desc = &dvb_pll_tdvs_tua6034; + dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_5_gold, + &dev->core->i2c_adap); + } + break; #endif default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 7f598039e0257..761cebd40dbda 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -1,5 +1,4 @@ /* - $Id: cx88-i2c.c,v 1.30 2005/07/25 05:10:13 mkrufky Exp $ cx88-i2c.c -- all the i2c code is here diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 2148877981921..d7980c51478d3 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-input.c,v 1.15 2005/07/07 13:58:38 mchehab Exp $ * * Device driver for GPIO attached remote control interfaces * on Conexant 2388x based TV/DVB cards. @@ -212,6 +211,53 @@ static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = { /* ---------------------------------------------------------------------- */ +/* Cinergy 1400 DVB-T */ +static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = { + [0x01] = KEY_POWER, + [0x02] = KEY_1, + [0x03] = KEY_2, + [0x04] = KEY_3, + [0x05] = KEY_4, + [0x06] = KEY_5, + [0x07] = KEY_6, + [0x08] = KEY_7, + [0x09] = KEY_8, + [0x0a] = KEY_9, + [0x0c] = KEY_0, + + [0x0b] = KEY_VIDEO, + [0x0d] = KEY_REFRESH, + [0x0e] = KEY_SELECT, + [0x0f] = KEY_EPG, + [0x10] = KEY_UP, + [0x11] = KEY_LEFT, + [0x12] = KEY_OK, + [0x13] = KEY_RIGHT, + [0x14] = KEY_DOWN, + [0x15] = KEY_TEXT, + [0x16] = KEY_INFO, + + [0x17] = KEY_RED, + [0x18] = KEY_GREEN, + [0x19] = KEY_YELLOW, + [0x1a] = KEY_BLUE, + + [0x1b] = KEY_CHANNELUP, + [0x1c] = KEY_VOLUMEUP, + [0x1d] = KEY_MUTE, + [0x1e] = KEY_VOLUMEDOWN, + [0x1f] = KEY_CHANNELDOWN, + + [0x40] = KEY_PAUSE, + [0x4c] = KEY_PLAY, + [0x58] = KEY_RECORD, + [0x54] = KEY_PREVIOUS, + [0x48] = KEY_STOP, + [0x5c] = KEY_NEXT, +}; + +/* ---------------------------------------------------------------------- */ + struct cx88_IR { struct cx88_core *core; struct input_dev input; @@ -241,7 +287,7 @@ module_param(ir_debug, int, 0644); /* debug level [IR] */ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define ir_dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s IR: " fmt , ir->core->name, ## arg) + printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg) /* ---------------------------------------------------------------------- */ @@ -329,6 +375,11 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keyup = 0x60; ir->polling = 50; /* ms */ break; + case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: + ir_codes = ir_codes_cinergy_1400; + ir_type = IR_TYPE_PD; + ir->sampling = 1; + break; case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: ir_codes = ir_codes_hauppauge_new; @@ -445,7 +496,7 @@ int cx88_ir_fini(struct cx88_core *core) void cx88_ir_irq(struct cx88_core *core) { struct cx88_IR *ir = core->ir; - u32 samples, rc5; + u32 samples, ircode; int i; if (NULL == ir) @@ -477,13 +528,44 @@ void cx88_ir_irq(struct cx88_core *core) /* decode it */ switch (core->board) { + case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: + ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4); + + if (ircode == 0xffffffff) { /* decoding error */ + ir_dprintk("pulse distance decoding error\n"); + break; + } + + ir_dprintk("pulse distance decoded: %x\n", ircode); + + if (ircode == 0) { /* key still pressed */ + ir_dprintk("pulse distance decoded repeat code\n"); + ir->release = jiffies + msecs_to_jiffies(120); + break; + } + + if ((ircode & 0xffff) != 0xeb04) { /* wrong address */ + ir_dprintk("pulse distance decoded wrong address\n"); + break; + } + + if (((~ircode >> 24) & 0xff) != ((ircode >> 16) & 0xff)) { /* wrong checksum */ + ir_dprintk("pulse distance decoded wrong check sum\n"); + break; + } + + ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f); + + ir_input_keydown(&ir->input, &ir->ir, (ircode >> 16) & 0x7f, (ircode >> 16) & 0xff); + ir->release = jiffies + msecs_to_jiffies(120); + break; case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: - rc5 = ir_decode_biphase(ir->samples, ir->scount, 5, 7); - ir_dprintk("biphase decoded: %x\n", rc5); - if ((rc5 & 0xfffff000) != 0x3000) + ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); + ir_dprintk("biphase decoded: %x\n", ircode); + if ((ircode & 0xfffff000) != 0x3000) break; - ir_input_keydown(&ir->input, &ir->ir, rc5 & 0x3f, rc5); + ir_input_keydown(&ir->input, &ir->ir, ircode & 0x3f, ircode); ir->release = jiffies + msecs_to_jiffies(120); break; } diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index fe2767c0ff944..6d0d15c3a1c65 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-mpeg.c,v 1.31 2005/07/07 14:17:47 mchehab Exp $ * * Support for the mpeg transport stream transfers * PCI function #2 of the cx2388x. @@ -73,11 +72,15 @@ static int cx8802_start_dma(struct cx8802_dev *dev, udelay(100); cx_write(MO_PINMUX_IO, 0x00); cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); - if ((core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q) || - (core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T)) { + switch (core->board) { + case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: + case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: + case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: cx_write(TS_SOP_STAT, 1<<13); - } else { + break; + default: cx_write(TS_SOP_STAT, 0x00); + break; } cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); @@ -86,12 +89,10 @@ static int cx8802_start_dma(struct cx8802_dev *dev, if (cx88_boards[core->board].blackbird) { cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ - // cx_write(TS_F2_CMD_STAT_MM, 0x2900106); /* F2_CMD_STAT_MM defaults + master + memory space */ cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ udelay(100); cx_write(TS_HW_SOP_CNTRL, 0x408); /* mpeg start byte */ - //cx_write(TS_HW_SOP_CNTRL, 0x2F0BC0); /* mpeg start byte ts: 0x2F0BC0 ? */ cx_write(TS_VALERR_CNTRL, 0x2000); cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ @@ -106,7 +107,6 @@ static int cx8802_start_dma(struct cx8802_dev *dev, dprintk( 0, "setting the interrupt mask\n" ); cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04); cx_set(MO_TS_INTMSK, 0x1f0011); - //cx_write(MO_TS_INTMSK, 0x0f0011); /* start dma */ cx_set(MO_DEV_CNTRL2, (1<<5)); @@ -206,7 +206,6 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(0,"[%p/%d] %s - first active\n", buf, buf->vb.i, __FUNCTION__); - //udelay(100); } else { dprintk( 1, "queue is not empty - append to active\n" ); @@ -217,7 +216,6 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk( 1, "[%p/%d] %s - append to active\n", buf, buf->vb.i, __FUNCTION__); - //udelay(100); } } @@ -387,7 +385,6 @@ int cx8802_init_common(struct cx8802_dev *dev) dev->pci_lat,pci_resource_start(dev->pci,0)); /* initialize driver struct */ - init_MUTEX(&dev->lock); spin_lock_init(&dev->slock); /* init dma queue */ diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h index 37f82662d2651..0a3a62fc9bbb7 100644 --- a/drivers/media/video/cx88/cx88-reg.h +++ b/drivers/media/video/cx88/cx88-reg.h @@ -1,5 +1,4 @@ /* - $Id: cx88-reg.h,v 1.8 2005/07/07 13:58:38 mchehab Exp $ cx88x-hw.h - CX2388x register offsets @@ -40,6 +39,29 @@ #define CX88X_EN_TBFX 0x02 #define CX88X_EN_VSFX 0x04 +/* ---------------------------------------------------------------------- */ +/* PCI controller registers */ + +/* Command and Status Register */ +#define F0_CMD_STAT_MM 0x2f0004 +#define F1_CMD_STAT_MM 0x2f0104 +#define F2_CMD_STAT_MM 0x2f0204 +#define F3_CMD_STAT_MM 0x2f0304 +#define F4_CMD_STAT_MM 0x2f0404 + +/* Device Control #1 */ +#define F0_DEV_CNTRL1_MM 0x2f0040 +#define F1_DEV_CNTRL1_MM 0x2f0140 +#define F2_DEV_CNTRL1_MM 0x2f0240 +#define F3_DEV_CNTRL1_MM 0x2f0340 +#define F4_DEV_CNTRL1_MM 0x2f0440 + +/* Device Control #1 */ +#define F0_BAR0_MM 0x2f0010 +#define F1_BAR0_MM 0x2f0110 +#define F2_BAR0_MM 0x2f0210 +#define F3_BAR0_MM 0x2f0310 +#define F4_BAR0_MM 0x2f0410 /* ---------------------------------------------------------------------- */ /* DMA Controller registers */ diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 91207f10bae77..2765acee0285f 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -1,5 +1,4 @@ /* - $Id: cx88-tvaudio.c,v 1.37 2005/07/07 13:58:38 mchehab Exp $ cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver @@ -121,25 +120,19 @@ static void set_audio_registers(struct cx88_core *core, } static void set_audio_start(struct cx88_core *core, - u32 mode, u32 ctl) + u32 mode) { // mute cx_write(AUD_VOL_CTL, (1 << 6)); - // increase level of input by 12dB -// cx_write(AUD_AFE_12DB_EN, 0x0001); - cx_write(AUD_AFE_12DB_EN, 0x0000); - // start programming cx_write(AUD_CTL, 0x0000); cx_write(AUD_INIT, mode); cx_write(AUD_INIT_LD, 0x0001); cx_write(AUD_SOFT_RESET, 0x0001); - - cx_write(AUD_CTL, ctl); } -static void set_audio_finish(struct cx88_core *core) +static void set_audio_finish(struct cx88_core *core, u32 ctl) { u32 volume; @@ -154,25 +147,25 @@ static void set_audio_finish(struct cx88_core *core) cx_write(AUD_I2SOUTPUTCNTL, 1); cx_write(AUD_I2SCNTL, 0); //cx_write(AUD_APB_IN_RATE_ADJ, 0); + } else { + ctl |= EN_DAC_ENABLE; + cx_write(AUD_CTL, ctl); } - // finish programming + /* finish programming */ cx_write(AUD_SOFT_RESET, 0x0000); - // start audio processing - cx_set(AUD_CTL, EN_DAC_ENABLE); - - // unmute + /* unmute */ volume = cx_sread(SHADOW_AUD_VOL_CTL); cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume); } /* ----------------------------------------------------------- */ -static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap) +static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap, u32 mode) { static const struct rlist btsc[] = { - /* from dscaler */ + { AUD_AFE_12DB_EN, 0x00000001 }, { AUD_OUT1_SEL, 0x00000013 }, { AUD_OUT1_SHIFT, 0x00000000 }, { AUD_POLY0_DDS_CONSTANT, 0x0012010c }, @@ -206,9 +199,10 @@ static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap) { AUD_RDSI_SHIFT, 0x00000000 }, { AUD_RDSQ_SHIFT, 0x00000000 }, { AUD_POLYPH80SCALEFAC, 0x00000003 }, - { /* end of list */ }, + { /* end of list */ }, }; static const struct rlist btsc_sap[] = { + { AUD_AFE_12DB_EN, 0x00000001 }, { AUD_DBX_IN_GAIN, 0x00007200 }, { AUD_DBX_WBE_GAIN, 0x00006200 }, { AUD_DBX_SE_GAIN, 0x00006200 }, @@ -259,371 +253,400 @@ static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap) { AUD_RDSI_SHIFT, 0x00000000 }, { AUD_RDSQ_SHIFT, 0x00000000 }, { AUD_POLYPH80SCALEFAC, 0x00000003 }, - { /* end of list */ }, + { /* end of list */ }, }; - // dscaler: exactly taken from driver, - // dscaler: don't know why to set EN_FMRADIO_EN_RDS + mode |= EN_FMRADIO_EN_RDS; + if (sap) { dprintk("%s SAP (status: unknown)\n",__FUNCTION__); - set_audio_start(core, 0x0001, - EN_FMRADIO_EN_RDS | EN_BTSC_FORCE_SAP); + set_audio_start(core, SEL_SAP); set_audio_registers(core, btsc_sap); + set_audio_finish(core, mode); } else { dprintk("%s (status: known-good)\n",__FUNCTION__); - set_audio_start(core, 0x0001, - EN_FMRADIO_EN_RDS | EN_BTSC_AUTO_STEREO); + set_audio_start(core, SEL_BTSC); set_audio_registers(core, btsc); + set_audio_finish(core, mode); } - set_audio_finish(core); } static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo) { - /* This is probably weird.. - * Let's operate and find out. */ - - static const struct rlist nicam_l_mono[] = { - { AUD_ERRLOGPERIOD_R, 0x00000064 }, - { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, - { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, - { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, - - { AUD_PDF_DDS_CNST_BYTE2, 0x48 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x3D }, - { AUD_QAM_MODE, 0x00 }, - { AUD_PDF_DDS_CNST_BYTE0, 0xf5 }, - { AUD_PHACC_FREQ_8MSB, 0x3a }, - { AUD_PHACC_FREQ_8LSB, 0x4a }, - - { AUD_DEEMPHGAIN_R, 0x6680 }, - { AUD_DEEMPHNUMER1_R, 0x353DE }, - { AUD_DEEMPHNUMER2_R, 0x1B1 }, - { AUD_DEEMPHDENOM1_R, 0x0F3D0 }, - { AUD_DEEMPHDENOM2_R, 0x0 }, - { AUD_FM_MODE_ENABLE, 0x7 }, - { AUD_POLYPH80SCALEFAC, 0x3 }, - { AUD_AFE_12DB_EN, 0x1 }, - { AAGC_GAIN, 0x0 }, - { AAGC_HYST, 0x18 }, - { AAGC_DEF, 0x20 }, - { AUD_DN0_FREQ, 0x0 }, - { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 }, - { AUD_DCOC_0_SRC, 0x21 }, - { AUD_IIR1_0_SEL, 0x0 }, - { AUD_IIR1_0_SHIFT, 0x7 }, - { AUD_IIR1_1_SEL, 0x2 }, - { AUD_IIR1_1_SHIFT, 0x0 }, - { AUD_DCOC_1_SRC, 0x3 }, - { AUD_DCOC1_SHIFT, 0x0 }, - { AUD_DCOC_PASS_IN, 0x0 }, - { AUD_IIR1_2_SEL, 0x23 }, - { AUD_IIR1_2_SHIFT, 0x0 }, - { AUD_IIR1_3_SEL, 0x4 }, - { AUD_IIR1_3_SHIFT, 0x7 }, - { AUD_IIR1_4_SEL, 0x5 }, - { AUD_IIR1_4_SHIFT, 0x7 }, - { AUD_IIR3_0_SEL, 0x7 }, - { AUD_IIR3_0_SHIFT, 0x0 }, - { AUD_DEEMPH0_SRC_SEL, 0x11 }, - { AUD_DEEMPH0_SHIFT, 0x0 }, - { AUD_DEEMPH0_G0, 0x7000 }, - { AUD_DEEMPH0_A0, 0x0 }, - { AUD_DEEMPH0_B0, 0x0 }, - { AUD_DEEMPH0_A1, 0x0 }, - { AUD_DEEMPH0_B1, 0x0 }, - { AUD_DEEMPH1_SRC_SEL, 0x11 }, - { AUD_DEEMPH1_SHIFT, 0x0 }, - { AUD_DEEMPH1_G0, 0x7000 }, - { AUD_DEEMPH1_A0, 0x0 }, - { AUD_DEEMPH1_B0, 0x0 }, - { AUD_DEEMPH1_A1, 0x0 }, - { AUD_DEEMPH1_B1, 0x0 }, - { AUD_OUT0_SEL, 0x3F }, - { AUD_OUT1_SEL, 0x3F }, - { AUD_DMD_RA_DDS, 0x0F5C285 }, - { AUD_PLL_INT, 0x1E }, - { AUD_PLL_DDS, 0x0 }, - { AUD_PLL_FRAC, 0x0E542 }, - - // setup QAM registers - { AUD_RATE_ADJ1, 0x00000100 }, - { AUD_RATE_ADJ2, 0x00000200 }, - { AUD_RATE_ADJ3, 0x00000300 }, - { AUD_RATE_ADJ4, 0x00000400 }, - { AUD_RATE_ADJ5, 0x00000500 }, - { AUD_RATE_THRES_DMD, 0x000000C0 }, - { /* end of list */ }, - }; - - static const struct rlist nicam_l[] = { - // setup QAM registers - { AUD_RATE_ADJ1, 0x00000060 }, - { AUD_RATE_ADJ2, 0x000000F9 }, - { AUD_RATE_ADJ3, 0x000001CC }, - { AUD_RATE_ADJ4, 0x000002B3 }, - { AUD_RATE_ADJ5, 0x00000726 }, - { AUD_DEEMPHDENOM1_R, 0x0000F3D0 }, - { AUD_DEEMPHDENOM2_R, 0x00000000 }, - { AUD_ERRLOGPERIOD_R, 0x00000064 }, - { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, - { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, - { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, - { AUD_POLYPH80SCALEFAC, 0x00000003 }, - { AUD_DMD_RA_DDS, 0x00C00000 }, - { AUD_PLL_INT, 0x0000001E }, - { AUD_PLL_DDS, 0x00000000 }, - { AUD_PLL_FRAC, 0x0000E542 }, - { AUD_START_TIMER, 0x00000000 }, - { AUD_DEEMPHNUMER1_R, 0x000353DE }, - { AUD_DEEMPHNUMER2_R, 0x000001B1 }, - { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, - { AUD_QAM_MODE, 0x05 }, - { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, - { AUD_PHACC_FREQ_8MSB, 0x34 }, - { AUD_PHACC_FREQ_8LSB, 0x4C }, - { AUD_DEEMPHGAIN_R, 0x00006680 }, - { AUD_RATE_THRES_DMD, 0x000000C0 }, - { /* end of list */ }, - } ; - dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); - - if (!stereo) { - /* AM mono sound */ - set_audio_start(core, 0x0004, - 0x100c /* FIXME again */); - set_audio_registers(core, nicam_l_mono); - } else { - set_audio_start(core, 0x0010, - 0x1924 /* FIXME again */); - set_audio_registers(core, nicam_l); - } - set_audio_finish(core); + /* This is probably weird.. + * Let's operate and find out. */ + + static const struct rlist nicam_l_mono[] = { + { AUD_ERRLOGPERIOD_R, 0x00000064 }, + { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, + { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, + + { AUD_PDF_DDS_CNST_BYTE2, 0x48 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x3D }, + { AUD_QAM_MODE, 0x00 }, + { AUD_PDF_DDS_CNST_BYTE0, 0xf5 }, + { AUD_PHACC_FREQ_8MSB, 0x3a }, + { AUD_PHACC_FREQ_8LSB, 0x4a }, + + { AUD_DEEMPHGAIN_R, 0x6680 }, + { AUD_DEEMPHNUMER1_R, 0x353DE }, + { AUD_DEEMPHNUMER2_R, 0x1B1 }, + { AUD_DEEMPHDENOM1_R, 0x0F3D0 }, + { AUD_DEEMPHDENOM2_R, 0x0 }, + { AUD_FM_MODE_ENABLE, 0x7 }, + { AUD_POLYPH80SCALEFAC, 0x3 }, + { AUD_AFE_12DB_EN, 0x1 }, + { AAGC_GAIN, 0x0 }, + { AAGC_HYST, 0x18 }, + { AAGC_DEF, 0x20 }, + { AUD_DN0_FREQ, 0x0 }, + { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 }, + { AUD_DCOC_0_SRC, 0x21 }, + { AUD_IIR1_0_SEL, 0x0 }, + { AUD_IIR1_0_SHIFT, 0x7 }, + { AUD_IIR1_1_SEL, 0x2 }, + { AUD_IIR1_1_SHIFT, 0x0 }, + { AUD_DCOC_1_SRC, 0x3 }, + { AUD_DCOC1_SHIFT, 0x0 }, + { AUD_DCOC_PASS_IN, 0x0 }, + { AUD_IIR1_2_SEL, 0x23 }, + { AUD_IIR1_2_SHIFT, 0x0 }, + { AUD_IIR1_3_SEL, 0x4 }, + { AUD_IIR1_3_SHIFT, 0x7 }, + { AUD_IIR1_4_SEL, 0x5 }, + { AUD_IIR1_4_SHIFT, 0x7 }, + { AUD_IIR3_0_SEL, 0x7 }, + { AUD_IIR3_0_SHIFT, 0x0 }, + { AUD_DEEMPH0_SRC_SEL, 0x11 }, + { AUD_DEEMPH0_SHIFT, 0x0 }, + { AUD_DEEMPH0_G0, 0x7000 }, + { AUD_DEEMPH0_A0, 0x0 }, + { AUD_DEEMPH0_B0, 0x0 }, + { AUD_DEEMPH0_A1, 0x0 }, + { AUD_DEEMPH0_B1, 0x0 }, + { AUD_DEEMPH1_SRC_SEL, 0x11 }, + { AUD_DEEMPH1_SHIFT, 0x0 }, + { AUD_DEEMPH1_G0, 0x7000 }, + { AUD_DEEMPH1_A0, 0x0 }, + { AUD_DEEMPH1_B0, 0x0 }, + { AUD_DEEMPH1_A1, 0x0 }, + { AUD_DEEMPH1_B1, 0x0 }, + { AUD_OUT0_SEL, 0x3F }, + { AUD_OUT1_SEL, 0x3F }, + { AUD_DMD_RA_DDS, 0x0F5C285 }, + { AUD_PLL_INT, 0x1E }, + { AUD_PLL_DDS, 0x0 }, + { AUD_PLL_FRAC, 0x0E542 }, + + // setup QAM registers + { AUD_RATE_ADJ1, 0x00000100 }, + { AUD_RATE_ADJ2, 0x00000200 }, + { AUD_RATE_ADJ3, 0x00000300 }, + { AUD_RATE_ADJ4, 0x00000400 }, + { AUD_RATE_ADJ5, 0x00000500 }, + { AUD_RATE_THRES_DMD, 0x000000C0 }, + { /* end of list */ }, + }; + static const struct rlist nicam_l[] = { + // setup QAM registers + { AUD_RATE_ADJ1, 0x00000060 }, + { AUD_RATE_ADJ2, 0x000000F9 }, + { AUD_RATE_ADJ3, 0x000001CC }, + { AUD_RATE_ADJ4, 0x000002B3 }, + { AUD_RATE_ADJ5, 0x00000726 }, + { AUD_DEEMPHDENOM1_R, 0x0000F3D0 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_ERRLOGPERIOD_R, 0x00000064 }, + { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, + { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, + { AUD_POLYPH80SCALEFAC, 0x00000003 }, + { AUD_DMD_RA_DDS, 0x00C00000 }, + { AUD_PLL_INT, 0x0000001E }, + { AUD_PLL_DDS, 0x00000000 }, + { AUD_PLL_FRAC, 0x0000E542 }, + { AUD_START_TIMER, 0x00000000 }, + { AUD_DEEMPHNUMER1_R, 0x000353DE }, + { AUD_DEEMPHNUMER2_R, 0x000001B1 }, + { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, + { AUD_QAM_MODE, 0x05 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, + { AUD_PHACC_FREQ_8MSB, 0x34 }, + { AUD_PHACC_FREQ_8LSB, 0x4C }, + { AUD_DEEMPHGAIN_R, 0x00006680 }, + { AUD_RATE_THRES_DMD, 0x000000C0 }, + { /* end of list */ }, + } ; + dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); + + if (!stereo) { + /* AM Mono */ + set_audio_start(core, SEL_A2); + set_audio_registers(core, nicam_l_mono); + set_audio_finish(core, EN_A2_FORCE_MONO1); + } else { + /* Nicam Stereo */ + set_audio_start(core, SEL_NICAM); + set_audio_registers(core, nicam_l); + set_audio_finish(core, 0x1924); /* FIXME */ + } } static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo) { static const struct rlist pal_i_fm_mono[] = { - {AUD_ERRLOGPERIOD_R, 0x00000064}, - {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, - {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, - {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, - {AUD_PDF_DDS_CNST_BYTE2, 0x06}, - {AUD_PDF_DDS_CNST_BYTE1, 0x82}, - {AUD_PDF_DDS_CNST_BYTE0, 0x12}, - {AUD_QAM_MODE, 0x05}, - {AUD_PHACC_FREQ_8MSB, 0x3a}, - {AUD_PHACC_FREQ_8LSB, 0x93}, - {AUD_DMD_RA_DDS, 0x002a4f2f}, - {AUD_PLL_INT, 0x0000001e}, - {AUD_PLL_DDS, 0x00000004}, - {AUD_PLL_FRAC, 0x0000e542}, - {AUD_RATE_ADJ1, 0x00000100}, - {AUD_RATE_ADJ2, 0x00000200}, - {AUD_RATE_ADJ3, 0x00000300}, - {AUD_RATE_ADJ4, 0x00000400}, - {AUD_RATE_ADJ5, 0x00000500}, - {AUD_THR_FR, 0x00000000}, - {AUD_PILOT_BQD_1_K0, 0x0000755b}, - {AUD_PILOT_BQD_1_K1, 0x00551340}, - {AUD_PILOT_BQD_1_K2, 0x006d30be}, - {AUD_PILOT_BQD_1_K3, 0xffd394af}, - {AUD_PILOT_BQD_1_K4, 0x00400000}, - {AUD_PILOT_BQD_2_K0, 0x00040000}, - {AUD_PILOT_BQD_2_K1, 0x002a4841}, - {AUD_PILOT_BQD_2_K2, 0x00400000}, - {AUD_PILOT_BQD_2_K3, 0x00000000}, - {AUD_PILOT_BQD_2_K4, 0x00000000}, - {AUD_MODE_CHG_TIMER, 0x00000060}, - {AUD_AFE_12DB_EN, 0x00000001}, - {AAGC_HYST, 0x0000000a}, - {AUD_CORDIC_SHIFT_0, 0x00000007}, - {AUD_CORDIC_SHIFT_1, 0x00000007}, - {AUD_C1_UP_THR, 0x00007000}, - {AUD_C1_LO_THR, 0x00005400}, - {AUD_C2_UP_THR, 0x00005400}, - {AUD_C2_LO_THR, 0x00003000}, - {AUD_DCOC_0_SRC, 0x0000001a}, - {AUD_DCOC0_SHIFT, 0x00000000}, - {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, - {AUD_DCOC_PASS_IN, 0x00000003}, - {AUD_IIR3_0_SEL, 0x00000021}, - {AUD_DN2_AFC, 0x00000002}, - {AUD_DCOC_1_SRC, 0x0000001b}, - {AUD_DCOC1_SHIFT, 0x00000000}, - {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, - {AUD_IIR3_1_SEL, 0x00000023}, - {AUD_DN0_FREQ, 0x000035a3}, - {AUD_DN2_FREQ, 0x000029c7}, - {AUD_CRDC0_SRC_SEL, 0x00000511}, - {AUD_IIR1_0_SEL, 0x00000001}, - {AUD_IIR1_1_SEL, 0x00000000}, - {AUD_IIR3_2_SEL, 0x00000003}, - {AUD_IIR3_2_SHIFT, 0x00000000}, - {AUD_IIR3_0_SEL, 0x00000002}, - {AUD_IIR2_0_SEL, 0x00000021}, - {AUD_IIR2_0_SHIFT, 0x00000002}, - {AUD_DEEMPH0_SRC_SEL, 0x0000000b}, - {AUD_DEEMPH1_SRC_SEL, 0x0000000b}, - {AUD_POLYPH80SCALEFAC, 0x00000001}, - {AUD_START_TIMER, 0x00000000}, - { /* end of list */ }, + {AUD_ERRLOGPERIOD_R, 0x00000064}, + {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, + {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, + {AUD_PDF_DDS_CNST_BYTE2, 0x06}, + {AUD_PDF_DDS_CNST_BYTE1, 0x82}, + {AUD_PDF_DDS_CNST_BYTE0, 0x12}, + {AUD_QAM_MODE, 0x05}, + {AUD_PHACC_FREQ_8MSB, 0x3a}, + {AUD_PHACC_FREQ_8LSB, 0x93}, + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_PLL_INT, 0x0000001e}, + {AUD_PLL_DDS, 0x00000004}, + {AUD_PLL_FRAC, 0x0000e542}, + {AUD_RATE_ADJ1, 0x00000100}, + {AUD_RATE_ADJ2, 0x00000200}, + {AUD_RATE_ADJ3, 0x00000300}, + {AUD_RATE_ADJ4, 0x00000400}, + {AUD_RATE_ADJ5, 0x00000500}, + {AUD_THR_FR, 0x00000000}, + {AUD_PILOT_BQD_1_K0, 0x0000755b}, + {AUD_PILOT_BQD_1_K1, 0x00551340}, + {AUD_PILOT_BQD_1_K2, 0x006d30be}, + {AUD_PILOT_BQD_1_K3, 0xffd394af}, + {AUD_PILOT_BQD_1_K4, 0x00400000}, + {AUD_PILOT_BQD_2_K0, 0x00040000}, + {AUD_PILOT_BQD_2_K1, 0x002a4841}, + {AUD_PILOT_BQD_2_K2, 0x00400000}, + {AUD_PILOT_BQD_2_K3, 0x00000000}, + {AUD_PILOT_BQD_2_K4, 0x00000000}, + {AUD_MODE_CHG_TIMER, 0x00000060}, + {AUD_AFE_12DB_EN, 0x00000001}, + {AAGC_HYST, 0x0000000a}, + {AUD_CORDIC_SHIFT_0, 0x00000007}, + {AUD_CORDIC_SHIFT_1, 0x00000007}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, + {AUD_DCOC_0_SRC, 0x0000001a}, + {AUD_DCOC0_SHIFT, 0x00000000}, + {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, + {AUD_DCOC_PASS_IN, 0x00000003}, + {AUD_IIR3_0_SEL, 0x00000021}, + {AUD_DN2_AFC, 0x00000002}, + {AUD_DCOC_1_SRC, 0x0000001b}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, + {AUD_IIR3_1_SEL, 0x00000023}, + {AUD_DN0_FREQ, 0x000035a3}, + {AUD_DN2_FREQ, 0x000029c7}, + {AUD_CRDC0_SRC_SEL, 0x00000511}, + {AUD_IIR1_0_SEL, 0x00000001}, + {AUD_IIR1_1_SEL, 0x00000000}, + {AUD_IIR3_2_SEL, 0x00000003}, + {AUD_IIR3_2_SHIFT, 0x00000000}, + {AUD_IIR3_0_SEL, 0x00000002}, + {AUD_IIR2_0_SEL, 0x00000021}, + {AUD_IIR2_0_SHIFT, 0x00000002}, + {AUD_DEEMPH0_SRC_SEL, 0x0000000b}, + {AUD_DEEMPH1_SRC_SEL, 0x0000000b}, + {AUD_POLYPH80SCALEFAC, 0x00000001}, + {AUD_START_TIMER, 0x00000000}, + { /* end of list */ }, }; static const struct rlist pal_i_nicam[] = { - { AUD_RATE_ADJ1, 0x00000010 }, - { AUD_RATE_ADJ2, 0x00000040 }, - { AUD_RATE_ADJ3, 0x00000100 }, - { AUD_RATE_ADJ4, 0x00000400 }, - { AUD_RATE_ADJ5, 0x00001000 }, - // { AUD_DMD_RA_DDS, 0x00c0d5ce }, - { AUD_DEEMPHGAIN_R, 0x000023c2 }, - { AUD_DEEMPHNUMER1_R, 0x0002a7bc }, - { AUD_DEEMPHNUMER2_R, 0x0003023e }, - { AUD_DEEMPHDENOM1_R, 0x0000f3d0 }, - { AUD_DEEMPHDENOM2_R, 0x00000000 }, - { AUD_DEEMPHDENOM2_R, 0x00000000 }, - { AUD_ERRLOGPERIOD_R, 0x00000fff }, - { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff }, - { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff }, - { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f }, - { AUD_POLYPH80SCALEFAC, 0x00000003 }, - { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, - { AUD_PDF_DDS_CNST_BYTE0, 0x16 }, - { AUD_QAM_MODE, 0x05 }, - { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, - { AUD_PHACC_FREQ_8MSB, 0x3a }, - { AUD_PHACC_FREQ_8LSB, 0x93 }, - { /* end of list */ }, - }; - - dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); - - if (!stereo) { - // FM mono - set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1); + { AUD_RATE_ADJ1, 0x00000010 }, + { AUD_RATE_ADJ2, 0x00000040 }, + { AUD_RATE_ADJ3, 0x00000100 }, + { AUD_RATE_ADJ4, 0x00000400 }, + { AUD_RATE_ADJ5, 0x00001000 }, + // { AUD_DMD_RA_DDS, 0x00c0d5ce }, + { AUD_DEEMPHGAIN_R, 0x000023c2 }, + { AUD_DEEMPHNUMER1_R, 0x0002a7bc }, + { AUD_DEEMPHNUMER2_R, 0x0003023e }, + { AUD_DEEMPHDENOM1_R, 0x0000f3d0 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_ERRLOGPERIOD_R, 0x00000fff }, + { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff }, + { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f }, + { AUD_POLYPH80SCALEFAC, 0x00000003 }, + { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x16 }, + { AUD_QAM_MODE, 0x05 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, + { AUD_PHACC_FREQ_8MSB, 0x3a }, + { AUD_PHACC_FREQ_8LSB, 0x93 }, + { /* end of list */ }, + }; + + dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); + + if (!stereo) { + /* FM Mono */ + set_audio_start(core, SEL_A2); set_audio_registers(core, pal_i_fm_mono); - } else { - // Nicam Stereo - set_audio_start(core, 0x0010, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO); + set_audio_finish(core, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1); + } else { + /* Nicam Stereo */ + set_audio_start(core, SEL_NICAM); set_audio_registers(core, pal_i_nicam); - } - set_audio_finish(core); + set_audio_finish(core, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO); + } } -static void set_audio_standard_A2(struct cx88_core *core) +static void set_audio_standard_A2(struct cx88_core *core, u32 mode) { - /* from dscaler cvs */ static const struct rlist a2_common[] = { - { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, - { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, - { AUD_QAM_MODE, 0x05 }, - { AUD_PHACC_FREQ_8MSB, 0x34 }, - { AUD_PHACC_FREQ_8LSB, 0x4c }, - - { AUD_RATE_ADJ1, 0x00001000 }, - { AUD_RATE_ADJ2, 0x00002000 }, - { AUD_RATE_ADJ3, 0x00003000 }, - { AUD_RATE_ADJ4, 0x00004000 }, - { AUD_RATE_ADJ5, 0x00005000 }, - { AUD_THR_FR, 0x00000000 }, - { AAGC_HYST, 0x0000001a }, - { AUD_PILOT_BQD_1_K0, 0x0000755b }, - { AUD_PILOT_BQD_1_K1, 0x00551340 }, - { AUD_PILOT_BQD_1_K2, 0x006d30be }, - { AUD_PILOT_BQD_1_K3, 0xffd394af }, - { AUD_PILOT_BQD_1_K4, 0x00400000 }, - { AUD_PILOT_BQD_2_K0, 0x00040000 }, - { AUD_PILOT_BQD_2_K1, 0x002a4841 }, - { AUD_PILOT_BQD_2_K2, 0x00400000 }, - { AUD_PILOT_BQD_2_K3, 0x00000000 }, - { AUD_PILOT_BQD_2_K4, 0x00000000 }, - { AUD_MODE_CHG_TIMER, 0x00000040 }, - { AUD_START_TIMER, 0x00000200 }, - { AUD_AFE_12DB_EN, 0x00000000 }, - { AUD_CORDIC_SHIFT_0, 0x00000007 }, - { AUD_CORDIC_SHIFT_1, 0x00000007 }, - { AUD_DEEMPH0_G0, 0x00000380 }, - { AUD_DEEMPH1_G0, 0x00000380 }, - { AUD_DCOC_0_SRC, 0x0000001a }, - { AUD_DCOC0_SHIFT, 0x00000000 }, - { AUD_DCOC_0_SHIFT_IN0, 0x0000000a }, - { AUD_DCOC_0_SHIFT_IN1, 0x00000008 }, - { AUD_DCOC_PASS_IN, 0x00000003 }, - { AUD_IIR3_0_SEL, 0x00000021 }, - { AUD_DN2_AFC, 0x00000002 }, - { AUD_DCOC_1_SRC, 0x0000001b }, - { AUD_DCOC1_SHIFT, 0x00000000 }, - { AUD_DCOC_1_SHIFT_IN0, 0x0000000a }, - { AUD_DCOC_1_SHIFT_IN1, 0x00000008 }, - { AUD_IIR3_1_SEL, 0x00000023 }, - { AUD_RDSI_SEL, 0x00000017 }, - { AUD_RDSI_SHIFT, 0x00000000 }, - { AUD_RDSQ_SEL, 0x00000017 }, - { AUD_RDSQ_SHIFT, 0x00000000 }, - { AUD_POLYPH80SCALEFAC, 0x00000001 }, + {AUD_ERRLOGPERIOD_R, 0x00000064}, + {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, + {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, + {AUD_PDF_DDS_CNST_BYTE2, 0x06}, + {AUD_PDF_DDS_CNST_BYTE1, 0x82}, + {AUD_PDF_DDS_CNST_BYTE0, 0x12}, + {AUD_QAM_MODE, 0x05}, + {AUD_PHACC_FREQ_8MSB, 0x34}, + {AUD_PHACC_FREQ_8LSB, 0x4c}, + {AUD_RATE_ADJ1, 0x00000100}, + {AUD_RATE_ADJ2, 0x00000200}, + {AUD_RATE_ADJ3, 0x00000300}, + {AUD_RATE_ADJ4, 0x00000400}, + {AUD_RATE_ADJ5, 0x00000500}, + {AUD_THR_FR, 0x00000000}, + {AAGC_HYST, 0x0000001a}, + {AUD_PILOT_BQD_1_K0, 0x0000755b}, + {AUD_PILOT_BQD_1_K1, 0x00551340}, + {AUD_PILOT_BQD_1_K2, 0x006d30be}, + {AUD_PILOT_BQD_1_K3, 0xffd394af}, + {AUD_PILOT_BQD_1_K4, 0x00400000}, + {AUD_PILOT_BQD_2_K0, 0x00040000}, + {AUD_PILOT_BQD_2_K1, 0x002a4841}, + {AUD_PILOT_BQD_2_K2, 0x00400000}, + {AUD_PILOT_BQD_2_K3, 0x00000000}, + {AUD_PILOT_BQD_2_K4, 0x00000000}, + {AUD_MODE_CHG_TIMER, 0x00000040}, + {AUD_AFE_12DB_EN, 0x00000001}, + {AUD_CORDIC_SHIFT_0, 0x00000007}, + {AUD_CORDIC_SHIFT_1, 0x00000007}, + {AUD_DEEMPH0_G0, 0x00000380}, + {AUD_DEEMPH1_G0, 0x00000380}, + {AUD_DCOC_0_SRC, 0x0000001a}, + {AUD_DCOC0_SHIFT, 0x00000000}, + {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, + {AUD_DCOC_PASS_IN, 0x00000003}, + {AUD_IIR3_0_SEL, 0x00000021}, + {AUD_DN2_AFC, 0x00000002}, + {AUD_DCOC_1_SRC, 0x0000001b}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, + {AUD_IIR3_1_SEL, 0x00000023}, + {AUD_RDSI_SEL, 0x00000017}, + {AUD_RDSI_SHIFT, 0x00000000}, + {AUD_RDSQ_SEL, 0x00000017}, + {AUD_RDSQ_SHIFT, 0x00000000}, + {AUD_PLL_INT, 0x0000001e}, + {AUD_PLL_DDS, 0x00000000}, + {AUD_PLL_FRAC, 0x0000e542}, + {AUD_POLYPH80SCALEFAC, 0x00000001}, + {AUD_START_TIMER, 0x00000000}, + { /* end of list */ }, + }; + static const struct rlist a2_bg[] = { + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, { /* end of list */ }, }; - static const struct rlist a2_table1[] = { - // PAL-BG - { AUD_DMD_RA_DDS, 0x002a73bd }, - { AUD_C1_UP_THR, 0x00007000 }, - { AUD_C1_LO_THR, 0x00005400 }, - { AUD_C2_UP_THR, 0x00005400 }, - { AUD_C2_LO_THR, 0x00003000 }, + static const struct rlist a2_dk[] = { + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, + {AUD_DN0_FREQ, 0x00003a1c}, + {AUD_DN2_FREQ, 0x0000d2e0}, { /* end of list */ }, }; - static const struct rlist a2_table2[] = { - // PAL-DK - { AUD_DMD_RA_DDS, 0x002a73bd }, - { AUD_C1_UP_THR, 0x00007000 }, - { AUD_C1_LO_THR, 0x00005400 }, - { AUD_C2_UP_THR, 0x00005400 }, - { AUD_C2_LO_THR, 0x00003000 }, - { AUD_DN0_FREQ, 0x00003a1c }, - { AUD_DN2_FREQ, 0x0000d2e0 }, +/* unknown, probably NTSC-M */ + static const struct rlist a2_m[] = { + {AUD_DMD_RA_DDS, 0x002a0425}, + {AUD_C1_UP_THR, 0x00003c00}, + {AUD_C1_LO_THR, 0x00003000}, + {AUD_C2_UP_THR, 0x00006000}, + {AUD_C2_LO_THR, 0x00003c00}, + {AUD_DEEMPH0_A0, 0x00007a80}, + {AUD_DEEMPH1_A0, 0x00007a80}, + {AUD_DEEMPH0_G0, 0x00001200}, + {AUD_DEEMPH1_G0, 0x00001200}, + {AUD_DN0_FREQ, 0x0000283b}, + {AUD_DN1_FREQ, 0x00003418}, + {AUD_DN2_FREQ, 0x000029c7}, + {AUD_POLY0_DDS_CONSTANT, 0x000a7540}, { /* end of list */ }, }; - static const struct rlist a2_table3[] = { - // unknown, probably NTSC-M - { AUD_DMD_RA_DDS, 0x002a2873 }, - { AUD_C1_UP_THR, 0x00003c00 }, - { AUD_C1_LO_THR, 0x00003000 }, - { AUD_C2_UP_THR, 0x00006000 }, - { AUD_C2_LO_THR, 0x00003c00 }, - { AUD_DN0_FREQ, 0x00002836 }, - { AUD_DN1_FREQ, 0x00003418 }, - { AUD_DN2_FREQ, 0x000029c7 }, - { AUD_POLY0_DDS_CONSTANT, 0x000a7540 }, + + static const struct rlist a2_deemph50[] = { + {AUD_DEEMPH0_G0, 0x00000380}, + {AUD_DEEMPH1_G0, 0x00000380}, + {AUD_DEEMPHGAIN_R, 0x000011e1}, + {AUD_DEEMPHNUMER1_R, 0x0002a7bc}, + {AUD_DEEMPHNUMER2_R, 0x0003023c}, + { /* end of list */ }, + }; + + static const struct rlist a2_deemph75[] = { + {AUD_DEEMPH0_G0, 0x00000480}, + {AUD_DEEMPH1_G0, 0x00000480}, + {AUD_DEEMPHGAIN_R, 0x00009000}, + {AUD_DEEMPHNUMER1_R, 0x000353de}, + {AUD_DEEMPHNUMER2_R, 0x000001b1}, { /* end of list */ }, }; - set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO); + set_audio_start(core, SEL_A2); set_audio_registers(core, a2_common); switch (core->tvaudio) { case WW_A2_BG: dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__); - set_audio_registers(core, a2_table1); + set_audio_registers(core, a2_bg); + set_audio_registers(core, a2_deemph50); break; case WW_A2_DK: dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__); - set_audio_registers(core, a2_table2); + set_audio_registers(core, a2_dk); + set_audio_registers(core, a2_deemph50); break; case WW_A2_M: dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__); - set_audio_registers(core, a2_table3); + set_audio_registers(core, a2_m); + set_audio_registers(core, a2_deemph75); break; }; - set_audio_finish(core); + + mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF; + set_audio_finish(core, mode); } static void set_audio_standard_EIAJ(struct cx88_core *core) @@ -635,9 +658,9 @@ static void set_audio_standard_EIAJ(struct cx88_core *core) }; dprintk("%s (status: unknown)\n",__FUNCTION__); - set_audio_start(core, 0x0002, EN_EIAJ_AUTO_STEREO); + set_audio_start(core, SEL_EIAJ); set_audio_registers(core, eiaj); - set_audio_finish(core); + set_audio_finish(core, EN_EIAJ_AUTO_STEREO); } static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type deemph) @@ -683,7 +706,7 @@ static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type }; dprintk("%s (status: unknown)\n",__FUNCTION__); - set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO); + set_audio_start(core, SEL_FMRADIO); switch (deemph) { @@ -700,7 +723,7 @@ static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type break; } - set_audio_finish(core); + set_audio_finish(core, EN_FMRADIO_AUTO_STEREO); } /* ----------------------------------------------------------- */ @@ -709,7 +732,7 @@ void cx88_set_tvaudio(struct cx88_core *core) { switch (core->tvaudio) { case WW_BTSC: - set_audio_standard_BTSC(core,0); + set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); break; case WW_NICAM_BGDKL: set_audio_standard_NICAM_L(core,0); @@ -720,7 +743,7 @@ void cx88_set_tvaudio(struct cx88_core *core) case WW_A2_BG: case WW_A2_DK: case WW_A2_M: - set_audio_standard_A2(core); + set_audio_standard_A2(core, EN_A2_FORCE_MONO1); break; case WW_EIAJ: set_audio_standard_EIAJ(core); @@ -734,7 +757,7 @@ void cx88_set_tvaudio(struct cx88_core *core) case WW_NONE: default: printk("%s/0: unknown tv audio mode [%d]\n", - core->name, core->tvaudio); + core->name, core->tvaudio); break; } return; @@ -769,6 +792,13 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) aud_ctl_names[cx_read(AUD_CTL) & 63]); core->astat = reg; +/* TODO + Reading from AUD_STATUS is not enough + for auto-detecting sap/dual-fm/nicam. + Add some code here later. +*/ + +# if 0 t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; t->rxsubchans = V4L2_TUNER_SUB_MONO; @@ -779,7 +809,7 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP; t->rxsubchans = V4L2_TUNER_SUB_STEREO; - if (1 == pilot) { + if (1 == pilot) { /* SAP */ t->rxsubchans |= V4L2_TUNER_SUB_SAP; } @@ -787,13 +817,13 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) case WW_A2_BG: case WW_A2_DK: case WW_A2_M: - if (1 == pilot) { + if (1 == pilot) { /* stereo */ t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; if (0 == mode) t->audmode = V4L2_TUNER_MODE_STEREO; } - if (2 == pilot) { + if (2 == pilot) { /* dual language -- FIXME */ t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; t->audmode = V4L2_TUNER_MODE_LANG1; @@ -805,16 +835,17 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) t->rxsubchans |= V4L2_TUNER_SUB_STEREO; } break; - case WW_SYSTEM_L_AM: - if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) { - t->audmode = V4L2_TUNER_MODE_STEREO; + case WW_SYSTEM_L_AM: + if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) { + t->audmode = V4L2_TUNER_MODE_STEREO; t->rxsubchans |= V4L2_TUNER_SUB_STEREO; } - break ; + break ; default: /* nothing */ break; } +# endif return; } @@ -835,16 +866,16 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) case WW_BTSC: switch (mode) { case V4L2_TUNER_MODE_MONO: - ctl = EN_BTSC_FORCE_MONO; - mask = 0x3f; + set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_MONO); break; - case V4L2_TUNER_MODE_SAP: - ctl = EN_BTSC_FORCE_SAP; - mask = 0x3f; + case V4L2_TUNER_MODE_LANG1: + set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); + break; + case V4L2_TUNER_MODE_LANG2: + set_audio_standard_BTSC(core, 1, EN_BTSC_FORCE_SAP); break; case V4L2_TUNER_MODE_STEREO: - ctl = EN_BTSC_AUTO_STEREO; - mask = 0x3f; + set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_STEREO); break; } break; @@ -854,16 +885,13 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) switch (mode) { case V4L2_TUNER_MODE_MONO: case V4L2_TUNER_MODE_LANG1: - ctl = EN_A2_FORCE_MONO1; - mask = 0x3f; + set_audio_standard_A2(core, EN_A2_FORCE_MONO1); break; case V4L2_TUNER_MODE_LANG2: - ctl = EN_A2_AUTO_MONO2; - mask = 0x3f; + set_audio_standard_A2(core, EN_A2_FORCE_MONO2); break; case V4L2_TUNER_MODE_STEREO: - ctl = EN_A2_AUTO_STEREO | EN_DMTRX_SUMR; - mask = 0x8bf; + set_audio_standard_A2(core, EN_A2_FORCE_STEREO); break; } break; diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 320d57888bbd9..9bc6c89955816 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-vbi.c,v 1.17 2005/06/12 04:19:19 mchehab Exp $ */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 5f58c103198af..61d4b29ec3026 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-video.c,v 1.82 2005/07/22 05:13:34 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * video4linux video interface @@ -66,7 +65,7 @@ module_param(vid_limit,int,0644); MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); #define dprintk(level,fmt, arg...) if (video_debug >= level) \ - printk(KERN_DEBUG "%s/0: " fmt, dev->core->name , ## arg) + printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) /* ------------------------------------------------------------------ */ @@ -326,22 +325,23 @@ static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls); static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bit) { + struct cx88_core *core = dev->core; if (fh->resources & bit) /* have it already allocated */ return 1; /* is it free? */ - down(&dev->lock); + down(&core->lock); if (dev->resources & bit) { /* no, someone else uses it */ - up(&dev->lock); + up(&core->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; dev->resources |= bit; dprintk(1,"res: get %d\n",bit); - up(&dev->lock); + up(&core->lock); return 1; } @@ -360,27 +360,29 @@ int res_locked(struct cx8800_dev *dev, unsigned int bit) static void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits) { + struct cx88_core *core = dev->core; if ((fh->resources & bits) != bits) BUG(); - down(&dev->lock); + down(&core->lock); fh->resources &= ~bits; dev->resources &= ~bits; dprintk(1,"res: put %d\n",bits); - up(&dev->lock); + up(&core->lock); } /* ------------------------------------------------------------------ */ -static int video_mux(struct cx8800_dev *dev, unsigned int input) +/* static int video_mux(struct cx8800_dev *dev, unsigned int input) */ +static int video_mux(struct cx88_core *core, unsigned int input) { - struct cx88_core *core = dev->core; + /* struct cx88_core *core = dev->core; */ dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", input, INPUT(input)->vmux, INPUT(input)->gpio0,INPUT(input)->gpio1, INPUT(input)->gpio2,INPUT(input)->gpio3); - dev->core->input = input; + core->input = input; cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input)->vmux << 14); cx_write(MO_GP3_IO, INPUT(input)->gpio3); cx_write(MO_GP0_IO, INPUT(input)->gpio0); @@ -413,9 +415,9 @@ static int start_video_dma(struct cx8800_dev *dev, struct cx88_core *core = dev->core; /* setup fifo + format */ - cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH21], + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], buf->bpl, buf->risc.dma); - cx88_set_scale(dev->core, buf->vb.width, buf->vb.height, buf->vb.field); + cx88_set_scale(core, buf->vb.width, buf->vb.height, buf->vb.field); cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma); /* reset counter */ @@ -424,6 +426,14 @@ static int start_video_dma(struct cx8800_dev *dev, /* enable irqs */ cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); + + /* Enables corresponding bits at PCI_INT_STAT: + bits 0 to 4: video, audio, transport stream, VIP, Host + bit 7: timer + bits 8 and 9: DMA complete for: SRC, DST + bits 10 and 11: BERR signal asserted for RISC: RD, WR + bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB + */ cx_set(MO_VID_INTMSK, 0x0f0011); /* enable capture */ @@ -431,7 +441,7 @@ static int start_video_dma(struct cx8800_dev *dev, /* start dma */ cx_set(MO_DEV_CNTRL2, (1<<5)); - cx_set(MO_VID_DMACNTRL, 0x11); + cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */ return 0; } @@ -455,6 +465,7 @@ static int stop_video_dma(struct cx8800_dev *dev) static int restart_video_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q) { + struct cx88_core *core = dev->core; struct cx88_buffer *buf, *prev; struct list_head *item; @@ -524,12 +535,13 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, { struct cx8800_fh *fh = q->priv_data; struct cx8800_dev *dev = fh->dev; + struct cx88_core *core = dev->core; struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); int rc, init_buffer = 0; BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > norm_maxw(dev->core->tvnorm) || - fh->height < 32 || fh->height > norm_maxh(dev->core->tvnorm)) + if (fh->width < 48 || fh->width > norm_maxw(core->tvnorm) || + fh->height < 32 || fh->height > norm_maxh(core->tvnorm)) return -EINVAL; buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) @@ -609,6 +621,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) struct cx88_buffer *prev; struct cx8800_fh *fh = vq->priv_data; struct cx8800_dev *dev = fh->dev; + struct cx88_core *core = dev->core; struct cx88_dmaqueue *q = &dev->vidq; /* add jump to stopper */ @@ -701,6 +714,7 @@ static int video_open(struct inode *inode, struct file *file) { int minor = iminor(inode); struct cx8800_dev *h,*dev = NULL; + struct cx88_core *core; struct cx8800_fh *fh; struct list_head *list; enum v4l2_buf_type type = 0; @@ -725,6 +739,8 @@ static int video_open(struct inode *inode, struct file *file) if (NULL == dev) return -ENODEV; + core = dev->core; + dprintk(1,"open minor=%d radio=%d type=%s\n", minor,radio,v4l2_type_names[type]); @@ -755,17 +771,16 @@ static int video_open(struct inode *inode, struct file *file) fh); if (fh->radio) { - struct cx88_core *core = dev->core; int board = core->board; dprintk(1,"video_open: setting radio device\n"); cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3); cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0); cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1); cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2); - dev->core->tvaudio = WW_FM; + core->tvaudio = WW_FM; cx88_set_tvaudio(core); cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); - cx88_call_i2c_clients(dev->core,AUDC_SET_RADIO,NULL); + cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL); } return 0; @@ -857,6 +872,9 @@ static int video_release(struct inode *inode, struct file *file) videobuf_mmap_free(&fh->vbiq); file->private_data = NULL; kfree(fh); + + cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); + return 0; } @@ -870,9 +888,10 @@ video_mmap(struct file *file, struct vm_area_struct * vma) /* ------------------------------------------------------------------ */ -static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) +/* static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */ +static int get_control(struct cx88_core *core, struct v4l2_control *ctl) { - struct cx88_core *core = dev->core; + /* struct cx88_core *core = dev->core; */ struct cx88_ctrl *c = NULL; u32 value; int i; @@ -898,9 +917,10 @@ static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) return 0; } -static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) +/* static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */ +static int set_control(struct cx88_core *core, struct v4l2_control *ctl) { - struct cx88_core *core = dev->core; + /* struct cx88_core *core = dev->core; */ struct cx88_ctrl *c = NULL; u32 v_sat_value; u32 value; @@ -913,9 +933,9 @@ static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) return -EINVAL; if (ctl->value < c->v.minimum) - return -ERANGE; + ctl->value = c->v.minimum; if (ctl->value > c->v.maximum) - return -ERANGE; + ctl->value = c->v.maximum; switch (ctl->id) { case V4L2_CID_AUDIO_BALANCE: value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value; @@ -946,7 +966,8 @@ static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) return 0; } -static void init_controls(struct cx8800_dev *dev) +/* static void init_controls(struct cx8800_dev *dev) */ +static void init_controls(struct cx88_core *core) { static struct v4l2_control mute = { .id = V4L2_CID_AUDIO_MUTE, @@ -969,11 +990,11 @@ static void init_controls(struct cx8800_dev *dev) .value = 0x80, }; - set_control(dev,&mute); - set_control(dev,&volume); - set_control(dev,&hue); - set_control(dev,&contrast); - set_control(dev,&brightness); + set_control(core,&mute); + set_control(core,&volume); + set_control(core,&hue); + set_control(core,&contrast); + set_control(core,&brightness); } /* ------------------------------------------------------------------ */ @@ -1004,6 +1025,8 @@ static int cx8800_g_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, struct v4l2_format *f) { + struct cx88_core *core = dev->core; + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { @@ -1016,8 +1039,8 @@ static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, return -EINVAL; field = f->fmt.pix.field; - maxw = norm_maxw(dev->core->tvnorm); - maxh = norm_maxh(dev->core->tvnorm); + maxw = norm_maxw(core->tvnorm); + maxh = norm_maxh(core->tvnorm); if (V4L2_FIELD_ANY == field) { field = (f->fmt.pix.height > maxh/2) @@ -1101,12 +1124,14 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (video_debug > 1) cx88_print_ioctl(core->name,cmd); switch (cmd) { + + /* --- capabilities ------------------------------------------ */ case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "cx8800"); + strcpy(cap->driver, "cx8800"); strlcpy(cap->card, cx88_boards[core->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); @@ -1116,12 +1141,128 @@ static int video_do_ioctl(struct inode *inode, struct file *file, V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_VIDEO_OVERLAY | 0; if (UNSET != core->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; } + /* --- capture ioctls ---------------------------------------- */ + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *f = arg; + enum v4l2_buf_type type; + unsigned int index; + + index = f->index; + type = f->type; + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (index >= ARRAY_SIZE(formats)) + return -EINVAL; + memset(f,0,sizeof(*f)); + f->index = index; + f->type = type; + strlcpy(f->description,formats[index].name,sizeof(f->description)); + f->pixelformat = formats[index].fourcc; + break; + default: + return -EINVAL; + } + return 0; + } + case VIDIOC_G_FMT: + { + struct v4l2_format *f = arg; + return cx8800_g_fmt(dev,fh,f); + } + case VIDIOC_S_FMT: + { + struct v4l2_format *f = arg; + return cx8800_s_fmt(dev,fh,f); + } + case VIDIOC_TRY_FMT: + { + struct v4l2_format *f = arg; + return cx8800_try_fmt(dev,fh,f); + } + + /* --- streaming capture ------------------------------------- */ + case VIDIOCGMBUF: + { + struct video_mbuf *mbuf = arg; + struct videobuf_queue *q; + struct v4l2_requestbuffers req; + unsigned int i; + + q = get_queue(fh); + memset(&req,0,sizeof(req)); + req.type = q->type; + req.count = 8; + req.memory = V4L2_MEMORY_MMAP; + err = videobuf_reqbufs(q,&req); + if (err < 0) + return err; + memset(mbuf,0,sizeof(*mbuf)); + mbuf->frames = req.count; + mbuf->size = 0; + for (i = 0; i < mbuf->frames; i++) { + mbuf->offsets[i] = q->bufs[i]->boff; + mbuf->size += q->bufs[i]->bsize; + } + return 0; + } + case VIDIOC_REQBUFS: + return videobuf_reqbufs(get_queue(fh), arg); + + case VIDIOC_QUERYBUF: + return videobuf_querybuf(get_queue(fh), arg); + + case VIDIOC_QBUF: + return videobuf_qbuf(get_queue(fh), arg); + + case VIDIOC_DQBUF: + return videobuf_dqbuf(get_queue(fh), arg, + file->f_flags & O_NONBLOCK); + + case VIDIOC_STREAMON: + { + int res = get_ressource(fh); + + if (!res_get(dev,fh,res)) + return -EBUSY; + return videobuf_streamon(get_queue(fh)); + } + case VIDIOC_STREAMOFF: + { + int res = get_ressource(fh); + + err = videobuf_streamoff(get_queue(fh)); + if (err < 0) + return err; + res_free(dev,fh,res); + return 0; + } + + default: + return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl ); + } + return 0; +} + +int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, + struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl) +{ + int err; + + if (video_debug > 1) + cx88_print_ioctl(core->name,cmd); + printk( KERN_INFO "CORE IOCTL: 0x%x\n", cmd ); + cx88_print_ioctl(core->name,cmd); + dprintk( 1, "CORE IOCTL: 0x%x\n", cmd ); + + switch (cmd) { /* ---------- tv norms ---------- */ case VIDIOC_ENUMSTD: { @@ -1156,9 +1297,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (i == ARRAY_SIZE(tvnorms)) return -EINVAL; - down(&dev->lock); - cx88_set_tvnorm(dev->core,&tvnorms[i]); - up(&dev->lock); + down(&core->lock); + cx88_set_tvnorm(core,&tvnorms[i]); + up(&core->lock); return 0; } @@ -1199,7 +1340,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, { unsigned int *i = arg; - *i = dev->core->input; + *i = core->input; return 0; } case VIDIOC_S_INPUT: @@ -1208,55 +1349,15 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (*i >= 4) return -EINVAL; - down(&dev->lock); + down(&core->lock); cx88_newstation(core); - video_mux(dev,*i); - up(&dev->lock); + video_mux(core,*i); + up(&core->lock); return 0; } - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - enum v4l2_buf_type type; - unsigned int index; - - index = f->index; - type = f->type; - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (index >= ARRAY_SIZE(formats)) - return -EINVAL; - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - strlcpy(f->description,formats[index].name,sizeof(f->description)); - f->pixelformat = formats[index].fourcc; - break; - default: - return -EINVAL; - } - return 0; - } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - return cx8800_g_fmt(dev,fh,f); - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - return cx8800_s_fmt(dev,fh,f); - } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = arg; - return cx8800_try_fmt(dev,fh,f); - } - /* --- controls ---------------------------------------------- */ case VIDIOC_QUERYCTRL: { @@ -1277,9 +1378,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file, return 0; } case VIDIOC_G_CTRL: - return get_control(dev,arg); + return get_control(core,arg); case VIDIOC_S_CTRL: - return set_control(dev,arg); + return set_control(core,arg); /* --- tuner ioctls ------------------------------------------ */ case VIDIOC_G_TUNER: @@ -1323,10 +1424,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (UNSET == core->tuner_type) return -EINVAL; - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->freq; + /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ + f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = core->freq; - cx88_call_i2c_clients(dev->core,VIDIOC_G_FREQUENCY,f); + cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); return 0; } @@ -1338,83 +1440,26 @@ static int video_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (f->tuner != 0) return -EINVAL; - if (0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV) + if (0 == radio && f->type != V4L2_TUNER_ANALOG_TV) return -EINVAL; - if (1 == fh->radio && f->type != V4L2_TUNER_RADIO) + if (1 == radio && f->type != V4L2_TUNER_RADIO) return -EINVAL; - down(&dev->lock); - dev->freq = f->frequency; + down(&core->lock); + core->freq = f->frequency; cx88_newstation(core); - cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f); + cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); /* When changing channels it is required to reset TVAUDIO */ msleep (10); cx88_set_tvaudio(core); - up(&dev->lock); - return 0; - } - - /* --- streaming capture ------------------------------------- */ - case VIDIOCGMBUF: - { - struct video_mbuf *mbuf = arg; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - - q = get_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - memset(mbuf,0,sizeof(*mbuf)); - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; - } - case VIDIOC_REQBUFS: - return videobuf_reqbufs(get_queue(fh), arg); - - case VIDIOC_QUERYBUF: - return videobuf_querybuf(get_queue(fh), arg); - - case VIDIOC_QBUF: - return videobuf_qbuf(get_queue(fh), arg); - - case VIDIOC_DQBUF: - return videobuf_dqbuf(get_queue(fh), arg, - file->f_flags & O_NONBLOCK); - - case VIDIOC_STREAMON: - { - int res = get_ressource(fh); - - if (!res_get(dev,fh,res)) - return -EBUSY; - return videobuf_streamon(get_queue(fh)); - } - case VIDIOC_STREAMOFF: - { - int res = get_ressource(fh); - - err = videobuf_streamoff(get_queue(fh)); - if (err < 0) - return err; - res_free(dev,fh,res); + up(&core->lock); return 0; } default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, - video_do_ioctl); + driver_ioctl); } return 0; } @@ -1461,7 +1506,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, memset(t,0,sizeof(*t)); strcpy(t->name, "Radio"); - cx88_call_i2c_clients(dev->core,VIDIOC_G_TUNER,t); + cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); return 0; } case VIDIOC_ENUMINPUT: @@ -1501,8 +1546,8 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, if (v->tuner) /* Only tuner 0 */ return -EINVAL; - cx88_call_i2c_clients(dev->core,VIDIOCSTUNER,v); - return 0; + cx88_call_i2c_clients(core,VIDIOCSTUNER,v); + return 0; } case VIDIOC_S_TUNER: { @@ -1511,7 +1556,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, if (0 != t->index) return -EINVAL; - cx88_call_i2c_clients(dev->core,VIDIOC_S_TUNER,t); + cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); return 0; } @@ -1569,7 +1614,7 @@ static void cx8800_vid_timeout(unsigned long data) struct cx88_buffer *buf; unsigned long flags; - cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH21]); + cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); cx_clear(MO_VID_DMACNTRL, 0x11); cx_clear(VID_CAPTURE_CONTROL, 0x06); @@ -1614,14 +1659,14 @@ static void cx8800_vid_irq(struct cx8800_dev *dev) printk(KERN_WARNING "%s/0: video risc op code error\n",core->name); cx_clear(MO_VID_DMACNTRL, 0x11); cx_clear(VID_CAPTURE_CONTROL, 0x06); - cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH21]); + cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); } /* risc1 y */ if (status & 0x01) { spin_lock(&dev->slock); count = cx_read(MO_VIDY_GPCNT); - cx88_wakeup(dev->core, &dev->vidq, count); + cx88_wakeup(core, &dev->vidq, count); spin_unlock(&dev->slock); } @@ -1629,7 +1674,7 @@ static void cx8800_vid_irq(struct cx8800_dev *dev) if (status & 0x08) { spin_lock(&dev->slock); count = cx_read(MO_VBI_GPCNT); - cx88_wakeup(dev->core, &dev->vbiq, count); + cx88_wakeup(core, &dev->vbiq, count); spin_unlock(&dev->slock); } @@ -1798,7 +1843,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, } /* initialize driver struct */ - init_MUTEX(&dev->lock); spin_lock_init(&dev->slock); core->tvnorm = tvnorms; @@ -1835,6 +1879,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, request_module("tuner"); if (core->tda9887_conf) request_module("tda9887"); + /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); @@ -1878,11 +1923,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, pci_set_drvdata(pci_dev,dev); /* initial device configuration */ - down(&dev->lock); - init_controls(dev); - cx88_set_tvnorm(dev->core,tvnorms); - video_mux(dev,0); - up(&dev->lock); + down(&core->lock); + init_controls(core); + cx88_set_tvnorm(core,tvnorms); + video_mux(core,0); + up(&core->lock); /* start tvaudio thread */ if (core->tuner_type != TUNER_ABSENT) @@ -1902,14 +1947,15 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, static void __devexit cx8800_finidev(struct pci_dev *pci_dev) { struct cx8800_dev *dev = pci_get_drvdata(pci_dev); + struct cx88_core *core = dev->core; /* stop thread */ - if (dev->core->kthread) { - kthread_stop(dev->core->kthread); - dev->core->kthread = NULL; + if (core->kthread) { + kthread_stop(core->kthread); + core->kthread = NULL; } - cx88_shutdown(dev->core); /* FIXME */ + cx88_shutdown(core); /* FIXME */ pci_disable_device(pci_dev); /* unregister stuff */ @@ -1921,7 +1967,7 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev) /* free memory */ btcx_riscmem_free(dev->pci,&dev->vidq.stopper); list_del(&dev->devlist); - cx88_core_put(dev->core,dev->pci); + cx88_core_put(core,dev->pci); kfree(dev); } @@ -1945,7 +1991,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) spin_unlock(&dev->slock); /* FIXME -- shutdown device */ - cx88_shutdown(dev->core); + cx88_shutdown(core); pci_save_state(pci_dev); if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { @@ -1968,7 +2014,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) pci_restore_state(pci_dev); /* FIXME: re-initialize hardware */ - cx88_reset(dev->core); + cx88_reset(core); /* restart video+vbi capture */ spin_lock(&dev->slock); @@ -2030,6 +2076,8 @@ static void cx8800_fini(void) module_init(cx8800_init); module_exit(cx8800_fini); +EXPORT_SYMBOL(cx88_do_ioctl); + /* ----------------------------------------------------------- */ /* * Local variables: diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index da65dc92787cd..13b8fb7e921a2 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -1,5 +1,4 @@ /* - * $Id: cx88.h,v 1.70 2005/07/24 17:44:09 mkrufky Exp $ * * v4l2 device driver for cx2388x based TV cards * @@ -48,6 +47,9 @@ #define CX88_MAXBOARDS 8 +/* Max number of inputs by card */ +#define MAX_CX88_INPUT 8 + /* ----------------------------------------------------------- */ /* defines and enums */ @@ -199,7 +201,7 @@ struct cx88_board { unsigned char tuner_addr; unsigned char radio_addr; int tda9887_conf; - struct cx88_input input[8]; + struct cx88_input input[MAX_CX88_INPUT]; struct cx88_input radio; int blackbird:1; int dvb:1; @@ -288,6 +290,11 @@ struct cx88_core { /* IR remote control state */ struct cx88_IR *ir; + + struct semaphore lock; + + /* various v4l controls */ + u32 freq; }; struct cx8800_dev; @@ -323,8 +330,7 @@ struct cx8800_suspend_state { struct cx8800_dev { struct cx88_core *core; struct list_head devlist; - struct semaphore lock; - spinlock_t slock; + spinlock_t slock; /* various device info */ unsigned int resources; @@ -342,7 +348,6 @@ struct cx8800_dev { struct cx88_dmaqueue vbiq; /* various v4l controls */ - u32 freq; /* other global state info */ struct cx8800_suspend_state state; @@ -350,14 +355,8 @@ struct cx8800_dev { /* ----------------------------------------------------------- */ /* function 1: audio/alsa stuff */ +/* =============> moved to cx88-alsa.c <====================== */ -struct cx8801_dev { - struct cx88_core *core; - - /* pci i/o */ - struct pci_dev *pci; - unsigned char pci_rev,pci_lat; -}; /* ----------------------------------------------------------- */ /* function 2: mpeg stuff */ @@ -373,8 +372,7 @@ struct cx8802_suspend_state { struct cx8802_dev { struct cx88_core *core; - struct semaphore lock; - spinlock_t slock; + spinlock_t slock; /* pci i/o */ struct pci_dev *pci; @@ -553,8 +551,21 @@ void cx8802_fini_common(struct cx8802_dev *dev); int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state); int cx8802_resume_common(struct pci_dev *pci_dev); +/* ----------------------------------------------------------- */ +/* cx88-video.c */ +extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, + struct cx88_core *core, unsigned int cmd, + void *arg, v4l2_kioctl driver_ioctl); + +/* ----------------------------------------------------------- */ +/* cx88-blackbird.c */ +extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd); + /* * Local variables: * c-basic-offset: 8 * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off */ -- GitLab From 2f1807102a3a5c9b9782b6e8d271fc8ccef91f0a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:46 -0700 Subject: [PATCH 180/563] [PATCH] v4l: SAA7134 updates and board additions - Remove $Id CVS logs for V4L files - linux/version.h replaced by linux/utsname.h - Add new Digimatrix card and LG TAPC Mini tuner for it Signed-off-by: Hermann Pitton <hermann.pitton@onlinehome.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 48 ++++++++++++++++++- drivers/media/video/saa7134/saa7134-core.c | 1 - drivers/media/video/saa7134/saa7134-dvb.c | 1 - drivers/media/video/saa7134/saa7134-empress.c | 1 - drivers/media/video/saa7134/saa7134-i2c.c | 1 - drivers/media/video/saa7134/saa7134-input.c | 1 - drivers/media/video/saa7134/saa7134-oss.c | 1 - drivers/media/video/saa7134/saa7134-reg.h | 1 - drivers/media/video/saa7134/saa7134-ts.c | 1 - drivers/media/video/saa7134/saa7134-tvaudio.c | 1 - drivers/media/video/saa7134/saa7134-vbi.c | 1 - drivers/media/video/saa7134/saa7134-video.c | 25 +--------- drivers/media/video/saa7134/saa7134.h | 4 +- 14 files changed, 51 insertions(+), 37 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 1b5a3a9ffbe2b..9c8b1ca1ccc08 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -62,3 +62,4 @@ 61 -> Philips TOUGH DVB-T reference design [1131:2004] 62 -> Compro VideoMate TV Gold+II 63 -> Kworld Xpert TV PVR7134 + 64 -> FlyTV mini Asus Digimatrix [1043:0210,1043:0210] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 88b71a20b602f..c277b3b46512f 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-cards.c,v 1.80 2005/07/07 01:49:30 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * card-specific stuff. @@ -2001,6 +2000,41 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x000, }, }, + [SAA7134_BOARD_FLYTV_DIGIMATRIX] = { + .name = "FlyTV mini Asus Digimatrix", + .audio_clock = 0x00200000, + .tuner_type = TUNER_LG_NTSC_TALN_MINI, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, /* radio unconfirmed */ + .amux = LINE2, + }, + }, }; @@ -2346,6 +2380,18 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x4e42, .subdevice = 0x0502, .driver_data = SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1043, + .subdevice = 0x0210, /* mini pci NTSC version */ + .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1043, + .subdevice = 0x0210, /* mini pci PAL/SECAM version */ + .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX, },{ /* --- boards without eeprom + subsystem ID --- */ diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 1dbe61755e9fc..e5e36f3c6250c 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-core.c,v 1.39 2005/07/05 17:37:35 nsh Exp $ * * device driver for philips saa7134 based TV cards * driver core diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 8be6a90358c84..fa29dd5f7f04c 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-dvb.c,v 1.23 2005/07/24 22:12:47 mkrufky Exp $ * * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] * diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index c85348d0239fd..77b627eb6483c 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-empress.c,v 1.11 2005/05/22 19:23:39 nsh Exp $ * * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] * diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index eae6b529713fe..711aa8e85fac3 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-i2c.c,v 1.22 2005/07/22 04:09:41 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * i2c interface support diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 213740122fe66..0e97b1eec20ef 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-input.c,v 1.21 2005/06/22 23:37:34 nsh Exp $ * * handle saa7134 IR remotes via linux kernel input layer. * diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index b5bede95dbf50..c20630c82f1c4 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-oss.c,v 1.17 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * oss dsp interface diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h index 87734f22af7d9..ae0c7a165390a 100644 --- a/drivers/media/video/saa7134/saa7134-reg.h +++ b/drivers/media/video/saa7134/saa7134-reg.h @@ -1,5 +1,4 @@ /* - * $Id: saa7134-reg.h,v 1.2 2004/09/15 16:15:24 kraxel Exp $ * * philips saa7134 registers */ diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 4dd9f1b239283..463885601ab43 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-ts.c,v 1.15 2005/06/14 22:48:18 hhackmann Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index eeafa5a71d2ba..badf2f9e3072b 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-tvaudio.c,v 1.30 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * tv audio decoder (fm stereo, nicam, ...) diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 29e51cad2aafa..f4aee0af80e19 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-vbi.c,v 1.7 2005/05/24 23:13:06 nsh Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index a4c2f751d0979..35e5e85f669a4 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-video.c,v 1.36 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface @@ -1368,29 +1367,7 @@ static int video_release(struct inode *inode, struct file *file) saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); - if (dev->tuner_type == TUNER_PHILIPS_TDA8290) { - u8 data[2]; - int ret; - struct i2c_msg msg = {.addr=I2C_ADDR_TDA8290, .flags=0, .buf=data, .len = 2}; - data[0] = 0x21; - data[1] = 0xc0; - ret = i2c_transfer(&dev->i2c_adap, &msg, 1); - if (ret != 1) - printk(KERN_ERR "TDA8290 access failure\n"); - msg.addr = I2C_ADDR_TDA8275; - data[0] = 0x30; - data[1] = 0xd0; - ret = i2c_transfer(&dev->i2c_adap, &msg, 1); - if (ret != 1) - printk(KERN_ERR "TDA8275 access failure\n"); - msg.addr = I2C_ADDR_TDA8290; - data[0] = 0x21; - data[1] = 0x80; - i2c_transfer(&dev->i2c_adap, &msg, 1); - data[0] = 0x00; - data[1] = 0x02; - i2c_transfer(&dev->i2c_adap, &msg, 1); - } + saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); /* free stuff */ videobuf_mmap_free(&fh->cap); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 2af0cb2a731b7..7a7fa42e1d22a 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -1,5 +1,4 @@ /* - * $Id: saa7134.h,v 1.49 2005/07/13 17:25:25 mchehab Exp $ * * v4l2 device driver for philips saa7134 based TV cards * @@ -20,7 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/version.h> +#include <linux/utsname.h> #define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,14) #include <linux/pci.h> @@ -185,6 +184,7 @@ struct saa7134_format { #define SAA7134_BOARD_PHILIPS_TOUGH 61 #define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62 #define SAA7134_BOARD_KWORLD_XPERT 63 +#define SAA7134_BOARD_FLYTV_DIGIMATRIX 64 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- GitLab From c0e9eae60e8f1a18e2e6502b3e738dd2886d18ff Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:47 -0700 Subject: [PATCH 181/563] [PATCH] v4l: change the prefix of msp34xx and error while reading chip version - Changes the prefix to 'msp34xx' instead of 'msp3400'. - Changes the message 'error while reading chip version' to a debug printk at msp3400.c Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/msp3400.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index ca02f6f14b000..01d567cf5c680 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -1452,7 +1452,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) client_template.addr = addr; if (-1 == msp3400c_reset(&client_template)) { - dprintk("msp3400: no chip found\n"); + dprintk("msp34xx: no chip found\n"); return -1; } @@ -1478,7 +1478,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) if (-1 == msp3400c_reset(c)) { kfree(msp); kfree(c); - dprintk("msp3400: no chip found\n"); + dprintk("msp34xx: no chip found\n"); return -1; } @@ -1488,7 +1488,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) { kfree(msp); kfree(c); - printk("msp3400: error while reading chip version\n"); + dprintk("msp34xx: error while reading chip version\n"); return -1; } -- GitLab From 272435dc44f7254c7174d69b41eb430a50583d1a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:47 -0700 Subject: [PATCH 182/563] [PATCH] v4l: syncs tveeprom tuners list with the list from ivtv - Syncs tveeprom tuners list with the list from ivtv. - Fixes the incorrect reporting of the radio presence. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/tveeprom.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index d0a00d3a6c4f6..367401449e3cc 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -152,7 +152,7 @@ hauppauge_tuner[] = { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, { TUNER_ABSENT, "LG TPI8NSR11F"}, { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, - { TUNER_ABSENT, "Philips FQ1216ME MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, { TUNER_ABSENT, "Philips FI1236 MK3"}, { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, @@ -167,7 +167,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Temic 4106FH5"}, { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, - { TUNER_ABSENT, "LG TAPE H701F MK3"}, + { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, /* 70-79 */ { TUNER_ABSENT, "LG TALN H200T"}, { TUNER_ABSENT, "LG TALN H250T"}, @@ -199,6 +199,13 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Philips FQ1236 MK5"}, { TUNER_ABSENT, "Unspecified"}, { TUNER_LG_PAL_TAPE, "LG PAL (TAPE Series)"}, + { TUNER_ABSENT, "Unspecified"}, + { TUNER_TCL_2002N, "TCL 2002N 5H"}, + /* 100-103 */ + { TUNER_ABSENT, "Unspecified"}, + { TUNER_ABSENT, "Unspecified"}, + { TUNER_ABSENT, "Unspecified"}, + { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05 4"}, }; static char *sndtype[] = { @@ -484,6 +491,7 @@ tveeprom_command(struct i2c_client *client, eeprom_props[1] = eeprom.tuner_formats; eeprom_props[2] = eeprom.model; eeprom_props[3] = eeprom.revision; + eeprom_props[4] = eeprom.has_radio; break; default: return -EINVAL; -- GitLab From 5adc1c306b1ce5b297bd8ee010a62f39cd32b9e4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:48 -0700 Subject: [PATCH 183/563] [PATCH] v4l: correct LG NTSC TALN mini tuner takeover - correct LG NTSC TALN mini tuner takeover as far we can empirically determine for now. Signed-off-by: Hermann Pitton <hermann.pitton@onlinehome.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/tuner-simple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 26034406b3721..6f153ca97492e 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -250,7 +250,7 @@ static struct tunertype tuners[] = { { "Ymec TVF66T5-B/DFF", Philips, PAL, 16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623}, { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC, - 16*150.00,16*425.00,0x01,0x02,0x08,0x8e,732 }, + 16*137.25,16*373.25,0x01,0x02,0x08,0x8e,732 }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); -- GitLab From 260784dcca44b5a526cece1f275cb81ccd186a3e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:49 -0700 Subject: [PATCH 184/563] [PATCH] v4l: add saa713x card #65 Kworld V-Stream Studio TV Terminator - Add saa713x card #65 Kworld V-Stream Studio TV Terminator Signed-off-by: James R Webb <jrwebb@qwest.net> Signed-off-by: Peter Missel <peter.missel@onlinehome.de> Signed-off-by: Nickolay V. Shmyrev <nshmyrev@yandex.ru> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 33 +++++++++++++++++++++ drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 35 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 9c8b1ca1ccc08..03512820f6c38 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -63,3 +63,4 @@ 62 -> Compro VideoMate TV Gold+II 63 -> Kworld Xpert TV PVR7134 64 -> FlyTV mini Asus Digimatrix [1043:0210,1043:0210] + 65 -> V-Stream Studio TV Terminator diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index c277b3b46512f..ea0237a0b563c 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2035,6 +2035,39 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }, }, + [SAA7134_BOARD_KWORLD_TERMINATOR] = { + /* Kworld V-Stream Studio TV Terminator */ + /* "James Webb <jrwebb@qwest.net> */ + .name = "V-Stream Studio TV Terminator", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 1 << 21, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .gpio = 0x0000000, + .tv = 1, + },{ + .name = name_comp1, /* Composite input */ + .vmux = 3, + .amux = LINE2, + .gpio = 0x0000000, + },{ + .name = name_svideo, /* S-Video input */ + .vmux = 8, + .amux = LINE2, + .gpio = 0x0000000, + }}, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0200000, + }, + }, }; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 7a7fa42e1d22a..26ec9446dff59 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -185,6 +185,7 @@ struct saa7134_format { #define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62 #define SAA7134_BOARD_KWORLD_XPERT 63 #define SAA7134_BOARD_FLYTV_DIGIMATRIX 64 +#define SAA7134_BOARD_KWORLD_TERMINATOR 65 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- GitLab From 4279f02478c2c4f106ec9efb80ca152e8d406844 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:51 -0700 Subject: [PATCH 185/563] [PATCH] v4l: add saa713x card #66: Yuan TUN-900 (saa7135) - Add saa713x card #66: Yuan TUN-900 (saa7135) Signed-off-by: De Greef Sebastien <sebdg@hotmail.com> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 41 +++++++++++++++++++++ drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 43 insertions(+) diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 03512820f6c38..dc57225f39be5 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -64,3 +64,4 @@ 63 -> Kworld Xpert TV PVR7134 64 -> FlyTV mini Asus Digimatrix [1043:0210,1043:0210] 65 -> V-Stream Studio TV Terminator + 66 -> Yuan TUN-900 (saa7135) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index ea0237a0b563c..f991f2325340c 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2068,6 +2068,47 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0200000, }, }, + [SAA7134_BOARD_YUAN_TUN900] = { + /* FIXME: + * S-Video and composite sources untested. + * Radio not working. + * Remote control not yet implemented. + * From : codemaster@webgeeks.be */ + .name = "Yuan TUN-900 (saa7135)", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr= ADDR_UNSET, + .radio_addr= ADDR_UNSET, + .gpiomask = 0x00010003, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x01, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + .gpio = 0x02, + },{ + .name = name_svideo, + .vmux = 6, + .amux = LINE2, + .gpio = 0x02, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + .gpio = 0x00010003, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x01, + }, + }, }; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 26ec9446dff59..1d70f3415e907 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -186,6 +186,7 @@ struct saa7134_format { #define SAA7134_BOARD_KWORLD_XPERT 63 #define SAA7134_BOARD_FLYTV_DIGIMATRIX 64 #define SAA7134_BOARD_KWORLD_TERMINATOR 65 +#define SAA7134_BOARD_YUAN_TUN900 66 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- GitLab From 10c35cf8fd89e166d13bc93175f2b05d9cb85e07 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:52 -0700 Subject: [PATCH 186/563] [PATCH] v4l: cx88-dvb incorrect reporting fixed and remove bad PCI ID for Sabrent - cx88-dvb has been incorrectly reporting the card name instead of frontend name - Removes a bad PCI subsystem ID for saa713x Sabrent card - Renames DVICO --> DViCO for bttv. - #include <linux/config.h> no longer needed. Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/video4linux/CARDLIST.bttv | 4 ++-- drivers/media/video/bttv-cards.c | 4 ++-- drivers/media/video/cx88/cx88-dvb.c | 6 ------ drivers/media/video/saa7134/saa7134-cards.c | 6 ------ 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv index 7979c060e787d..ec785f9f15a31 100644 --- a/Documentation/video4linux/CARDLIST.bttv +++ b/Documentation/video4linux/CARDLIST.bttv @@ -126,12 +126,12 @@ card=124 - AverMedia AverTV DVB-T 761 card=125 - MATRIX Vision Sigma-SQ card=126 - MATRIX Vision Sigma-SLC card=127 - APAC Viewcomp 878(AMAX) -card=128 - DVICO FusionHDTV DVB-T Lite +card=128 - DViCO FusionHDTV DVB-T Lite card=129 - V-Gear MyVCD card=130 - Super TV Tuner card=131 - Tibet Systems 'Progress DVR' CS16 card=132 - Kodicom 4400R (master) card=133 - Kodicom 4400R (slave) card=134 - Adlink RTV24 -card=135 - DVICO FusionHDTV 5 Lite +card=135 - DViCO FusionHDTV 5 Lite card=136 - Acorp Y878F diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 3cb398b7a0285..64785d3fe838e 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -2258,7 +2258,7 @@ struct tvcard bttv_tvcards[] = { /* ---- card 0x80 ---------------------------------- */ /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */ - .name = "DVICO FusionHDTV DVB-T Lite", + .name = "DViCO FusionHDTV DVB-T Lite", .tuner = -1, .no_msp34xx = 1, .no_tda9875 = 1, @@ -2389,7 +2389,7 @@ struct tvcard bttv_tvcards[] = { { /* ---- card 0x87---------------------------------- */ /* Michael Krufky <mkrufky@m1k.net> */ - .name = "DVICO FusionHDTV 5 Lite", + .name = "DViCO FusionHDTV 5 Lite", .tuner = 0, .tuner_type = TUNER_LG_TDVS_H062F, .tuner_addr = ADDR_UNSET, diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index cc71cafc2cbd9..c9106b1d79dff 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -28,7 +28,6 @@ #include <linux/kthread.h> #include <linux/file.h> #include <linux/suspend.h> -#include <linux/config.h> #include "cx88.h" @@ -403,11 +402,6 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max; } - /* Copy the board name into the DVB structure */ - strlcpy(dev->dvb.frontend->ops->info.name, - cx88_boards[dev->core->board].name, - sizeof(dev->dvb.frontend->ops->info.name)); - /* register everything */ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev); } diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index f991f2325340c..07d3ee0ada7d0 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2378,12 +2378,6 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x185b, .subdevice = 0xc100, .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0, - .driver_data = SAA7134_BOARD_SABRENT_SBTTVFM, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, -- GitLab From 1c94aeecd3fd2aed66d9a1135f5329df622e6137 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:52 -0700 Subject: [PATCH 187/563] [PATCH] v4l: normalize whitespace and comments in tuner lists - normalize whitespace and comments in tuner lists Signed-off-by: Philip Rowlands <phr@doc.ic.ac.uk> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/tuner-simple.c | 43 ++++---- include/media/tuner.h | 170 ++++++++++++++--------------- 2 files changed, 105 insertions(+), 108 deletions(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 6f153ca97492e..5e99b242a28d2 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -101,6 +101,7 @@ struct tunertype * "no float in kernel" rule. */ static struct tunertype tuners[] = { + /* 0-9 */ { "Temic PAL (4002 FH5)", TEMIC, PAL, 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623}, { "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I, @@ -109,7 +110,6 @@ static struct tunertype tuners[] = { 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM, 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623}, - { "NoTuner", NoTuner, NOTUNER, 0,0,0x00,0x00,0x00,0x00,0x00}, { "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL, @@ -118,34 +118,34 @@ static struct tunertype tuners[] = { 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, { "Temic PAL_I (4062 FY5)", TEMIC, PAL_I, 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, - { "Temic NTSC (4036 FY5)", TEMIC, NTSC, 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, { "Alps HSBH1", TEMIC, NTSC, 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, - { "Alps TSBE1",TEMIC,PAL, + + /* 10-19 */ + { "Alps TSBE1", TEMIC, PAL, 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */ 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, - { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, { "Temic PAL_BG (4006FH5)", TEMIC, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "Alps TSCH6",Alps,NTSC, + { "Alps TSCH6", Alps, NTSC, 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732}, - - { "Temic PAL_DK (4016 FY5)",TEMIC,PAL, + { "Temic PAL_DK (4016 FY5)", TEMIC, PAL, 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623}, - { "Philips NTSC_M (MK2)",Philips,NTSC, + { "Philips NTSC_M (MK2)", Philips, NTSC, 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I, 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, { "Temic PAL* auto (4006 FN5)", TEMIC, PAL, 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, + /* 20-29 */ { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "Temic NTSC (4039 FR5)", TEMIC, NTSC, @@ -154,7 +154,6 @@ static struct tunertype tuners[] = { 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, { "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I, @@ -163,25 +162,24 @@ static struct tunertype tuners[] = { 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, { "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC, 16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732}, - { "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, { "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + + /* 30-39 */ { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 }, - - { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ + { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, - { "MT20xx universal", Microtune,PAL|NTSC, + { "MT20xx universal", Microtune, PAL|NTSC, /* see mt20xx.c for details */ }, { "Temic PAL_BG (4106 FH5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL, 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623}, - { "Temic NTSC (4136 FY5)", TEMIC, NTSC, 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, { "LG PAL (newer TAPC series)", LGINNOTEK, PAL, @@ -191,42 +189,41 @@ static struct tunertype tuners[] = { { "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC, 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, + /* 40-49 */ { "HITACHI V7-J180AT", HITACHI, NTSC, 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 }, { "Philips PAL_MK (FI1216 MK)", Philips, PAL, 16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623}, - { "Philips 1236D ATSC/NTSC daul in",Philips,ATSC, + { "Philips 1236D ATSC/NTSC daul in", Philips, ATSC, 16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732}, { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, - { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, - { "Microtune 4049 FM5",Microtune,PAL, + { "Microtune 4049 FM5", Microtune, PAL, 16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623}, { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC, 16*160.00,16*454.00,0x01,0x02,0x08,0xce,940}, { "LG NTSC (TAPE series)", LGINNOTEK, NTSC, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, - { "Tenna TNF 8831 BGFF)", Philips, PAL, 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, { "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC, 16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732}, + + /* 50-59 */ { "TCL 2002N", TCL, NTSC, 16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732}, { "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, - { "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC, 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, { "Philips FQ1286", Philips, NTSC, - 16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, // UHF band untested - { "tda8290+75", Philips,PAL|NTSC, + 16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, /* UHF band untested */ + { "tda8290+75", Philips, PAL|NTSC, /* see tda8290.c for details */ }, { "LG PAL (TAPE series)", LGINNOTEK, PAL, 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623}, - { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL, 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 }, { "Philips FQ1236A MK4", Philips, NTSC, @@ -236,6 +233,7 @@ static struct tunertype tuners[] = { { "Ymec TVision TVF-5533MF", Philips, NTSC, 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732}, + /* 60-66 */ { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC, 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL, @@ -244,7 +242,6 @@ static struct tunertype tuners[] = { /* see tea5767.c for details */}, { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL, 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 }, - { "LG TDVS-H062F/TUA6034", LGINNOTEK, NTSC, 16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732}, { "Ymec TVF66T5-B/DFF", Philips, PAL, diff --git a/include/media/tuner.h b/include/media/tuner.h index 252673bfa592f..5b01ee6b08685 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -26,90 +26,90 @@ #define ADDR_UNSET (255) -#define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */ -#define TUNER_PHILIPS_PAL_I 1 -#define TUNER_PHILIPS_NTSC 2 -#define TUNER_PHILIPS_SECAM 3 /* you must actively select B/G, L, L` */ - -#define TUNER_ABSENT 4 -#define TUNER_PHILIPS_PAL 5 -#define TUNER_TEMIC_NTSC 6 /* 4032 FY5 (3X 7004, 9498, 9789) */ -#define TUNER_TEMIC_PAL_I 7 /* 4062 FY5 (3X 8501, 9957) */ - -#define TUNER_TEMIC_4036FY5_NTSC 8 /* 4036 FY5 (3X 1223, 1981, 7686) */ -#define TUNER_ALPS_TSBH1_NTSC 9 -#define TUNER_ALPS_TSBE1_PAL 10 -#define TUNER_ALPS_TSBB5_PAL_I 11 - -#define TUNER_ALPS_TSBE5_PAL 12 -#define TUNER_ALPS_TSBC5_PAL 13 -#define TUNER_TEMIC_4006FH5_PAL 14 /* 4006 FH5 (3X 9500, 9501, 7291) */ -#define TUNER_ALPS_TSHC6_NTSC 15 - -#define TUNER_TEMIC_PAL_DK 16 /* 4016 FY5 (3X 1392, 1393) */ -#define TUNER_PHILIPS_NTSC_M 17 -#define TUNER_TEMIC_4066FY5_PAL_I 18 /* 4066 FY5 (3X 7032, 7035) */ -#define TUNER_TEMIC_4006FN5_MULTI_PAL 19 /* B/G, I and D/K autodetected (3X 7595, 7606, 7657)*/ - -#define TUNER_TEMIC_4009FR5_PAL 20 /* incl. FM radio (3X 7607, 7488, 7711)*/ -#define TUNER_TEMIC_4039FR5_NTSC 21 /* incl. FM radio (3X 7246, 7578, 7732)*/ -#define TUNER_TEMIC_4046FM5 22 /* you must actively select B/G, D/K, I, L, L` ! (3X 7804, 7806, 8103, 8104)*/ +#define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */ +#define TUNER_PHILIPS_PAL_I 1 +#define TUNER_PHILIPS_NTSC 2 +#define TUNER_PHILIPS_SECAM 3 /* you must actively select B/G, L, L` */ + +#define TUNER_ABSENT 4 +#define TUNER_PHILIPS_PAL 5 +#define TUNER_TEMIC_NTSC 6 /* 4032 FY5 (3X 7004, 9498, 9789) */ +#define TUNER_TEMIC_PAL_I 7 /* 4062 FY5 (3X 8501, 9957) */ + +#define TUNER_TEMIC_4036FY5_NTSC 8 /* 4036 FY5 (3X 1223, 1981, 7686) */ +#define TUNER_ALPS_TSBH1_NTSC 9 +#define TUNER_ALPS_TSBE1_PAL 10 +#define TUNER_ALPS_TSBB5_PAL_I 11 + +#define TUNER_ALPS_TSBE5_PAL 12 +#define TUNER_ALPS_TSBC5_PAL 13 +#define TUNER_TEMIC_4006FH5_PAL 14 /* 4006 FH5 (3X 9500, 9501, 7291) */ +#define TUNER_ALPS_TSHC6_NTSC 15 + +#define TUNER_TEMIC_PAL_DK 16 /* 4016 FY5 (3X 1392, 1393) */ +#define TUNER_PHILIPS_NTSC_M 17 +#define TUNER_TEMIC_4066FY5_PAL_I 18 /* 4066 FY5 (3X 7032, 7035) */ +#define TUNER_TEMIC_4006FN5_MULTI_PAL 19 /* B/G, I and D/K autodetected (3X 7595, 7606, 7657) */ + +#define TUNER_TEMIC_4009FR5_PAL 20 /* incl. FM radio (3X 7607, 7488, 7711) */ +#define TUNER_TEMIC_4039FR5_NTSC 21 /* incl. FM radio (3X 7246, 7578, 7732) */ +#define TUNER_TEMIC_4046FM5 22 /* you must actively select B/G, D/K, I, L, L` ! (3X 7804, 7806, 8103, 8104) */ #define TUNER_PHILIPS_PAL_DK 23 -#define TUNER_PHILIPS_FQ1216ME 24 /* you must actively select B/G/D/K, I, L, L` */ -#define TUNER_LG_PAL_I_FM 25 -#define TUNER_LG_PAL_I 26 -#define TUNER_LG_NTSC_FM 27 +#define TUNER_PHILIPS_FQ1216ME 24 /* you must actively select B/G/D/K, I, L, L` */ +#define TUNER_LG_PAL_I_FM 25 +#define TUNER_LG_PAL_I 26 +#define TUNER_LG_NTSC_FM 27 -#define TUNER_LG_PAL_FM 28 -#define TUNER_LG_PAL 29 -#define TUNER_TEMIC_4009FN5_MULTI_PAL_FM 30 /* B/G, I and D/K autodetected (3X 8155, 8160, 8163)*/ -#define TUNER_SHARP_2U5JF5540_NTSC 31 +#define TUNER_LG_PAL_FM 28 +#define TUNER_LG_PAL 29 +#define TUNER_TEMIC_4009FN5_MULTI_PAL_FM 30 /* B/G, I and D/K autodetected (3X 8155, 8160, 8163) */ +#define TUNER_SHARP_2U5JF5540_NTSC 31 -#define TUNER_Samsung_PAL_TCPM9091PD27 32 -#define TUNER_MT2032 33 -#define TUNER_TEMIC_4106FH5 34 /* 4106 FH5 (3X 7808, 7865)*/ -#define TUNER_TEMIC_4012FY5 35 /* 4012 FY5 (3X 0971, 1099)*/ +#define TUNER_Samsung_PAL_TCPM9091PD27 32 +#define TUNER_MT2032 33 +#define TUNER_TEMIC_4106FH5 34 /* 4106 FH5 (3X 7808, 7865) */ +#define TUNER_TEMIC_4012FY5 35 /* 4012 FY5 (3X 0971, 1099) */ -#define TUNER_TEMIC_4136FY5 36 /* 4136 FY5 (3X 7708, 7746)*/ -#define TUNER_LG_PAL_NEW_TAPC 37 -#define TUNER_PHILIPS_FM1216ME_MK3 38 -#define TUNER_LG_NTSC_NEW_TAPC 39 +#define TUNER_TEMIC_4136FY5 36 /* 4136 FY5 (3X 7708, 7746) */ +#define TUNER_LG_PAL_NEW_TAPC 37 +#define TUNER_PHILIPS_FM1216ME_MK3 38 +#define TUNER_LG_NTSC_NEW_TAPC 39 -#define TUNER_HITACHI_NTSC 40 -#define TUNER_PHILIPS_PAL_MK 41 -#define TUNER_PHILIPS_ATSC 42 -#define TUNER_PHILIPS_FM1236_MK3 43 +#define TUNER_HITACHI_NTSC 40 +#define TUNER_PHILIPS_PAL_MK 41 +#define TUNER_PHILIPS_ATSC 42 +#define TUNER_PHILIPS_FM1236_MK3 43 -#define TUNER_PHILIPS_4IN1 44 /* ATI TV Wonder Pro - Conexant */ +#define TUNER_PHILIPS_4IN1 44 /* ATI TV Wonder Pro - Conexant */ /* Microtune mergeged with Temic 12/31/1999 partially financed by Alps - these may be similar to Temic */ -#define TUNER_MICROTUNE_4049FM5 45 -#define TUNER_LG_NTSC_TAPE 47 - -#define TUNER_TNF_8831BGFF 48 -#define TUNER_MICROTUNE_4042FI5 49 /* DViCO FusionHDTV 3 Gold-Q - 4042 FI5 (3X 8147) */ -#define TUNER_TCL_2002N 50 -#define TUNER_PHILIPS_FM1256_IH3 51 - -#define TUNER_THOMSON_DTT7610 52 -#define TUNER_PHILIPS_FQ1286 53 -#define TUNER_PHILIPS_TDA8290 54 -#define TUNER_LG_PAL_TAPE 55 /* Hauppauge PVR-150 PAL */ - -#define TUNER_PHILIPS_FQ1216AME_MK4 56 /* Hauppauge PVR-150 PAL */ -#define TUNER_PHILIPS_FQ1236A_MK4 57 /* Hauppauge PVR-500MCE NTSC */ - -#define TUNER_YMEC_TVF_8531MF 58 -#define TUNER_YMEC_TVF_5533MF 59 /* Pixelview Pro Ultra NTSC */ -#define TUNER_THOMSON_DTT7611 60 /* DViCO FusionHDTV 3 Gold-T */ -#define TUNER_TENA_9533_DI 61 - -#define TUNER_TEA5767 62 /* Only FM Radio Tuner */ -#define TUNER_PHILIPS_FMD1216ME_MK3 63 -#define TUNER_LG_TDVS_H062F 64 /* DViCO FusionHDTV 5 */ -#define TUNER_YMEC_TVF66T5_B_DFF 65 /* Acorp Y878F */ - -#define TUNER_LG_NTSC_TALN_MINI 66 +#define TUNER_MICROTUNE_4049FM5 45 +#define TUNER_MICROTUNE_4042_FI5 46 +#define TUNER_LG_NTSC_TAPE 47 + +#define TUNER_TNF_8831BGFF 48 +#define TUNER_MICROTUNE_4042FI5 49 /* DViCO FusionHDTV 3 Gold-Q - 4042 FI5 (3X 8147) */ +#define TUNER_TCL_2002N 50 +#define TUNER_PHILIPS_FM1256_IH3 51 + +#define TUNER_THOMSON_DTT7610 52 +#define TUNER_PHILIPS_FQ1286 53 +#define TUNER_PHILIPS_TDA8290 54 +#define TUNER_LG_PAL_TAPE 55 /* Hauppauge PVR-150 PAL */ + +#define TUNER_PHILIPS_FQ1216AME_MK4 56 /* Hauppauge PVR-150 PAL */ +#define TUNER_PHILIPS_FQ1236A_MK4 57 /* Hauppauge PVR-500MCE NTSC */ +#define TUNER_YMEC_TVF_8531MF 58 +#define TUNER_YMEC_TVF_5533MF 59 /* Pixelview Pro Ultra NTSC */ + +#define TUNER_THOMSON_DTT7611 60 /* DViCO FusionHDTV 3 Gold-T */ +#define TUNER_TENA_9533_DI 61 +#define TUNER_TEA5767 62 /* Only FM Radio Tuner */ +#define TUNER_PHILIPS_FMD1216ME_MK3 63 + +#define TUNER_LG_TDVS_H062F 64 /* DViCO FusionHDTV 5 */ +#define TUNER_YMEC_TVF66T5_B_DFF 65 /* Acorp Y878F */ +#define TUNER_LG_NTSC_TALN_MINI 66 #define NOTUNER 0 #define PAL 1 /* PAL_BG */ @@ -117,7 +117,7 @@ #define NTSC 3 #define SECAM 4 #define ATSC 5 -#define RADIO 6 +#define RADIO 6 #define NoTuner 0 #define Philips 1 @@ -163,21 +163,21 @@ enum tuner_mode { }; struct tuner_setup { - unsigned short addr; - unsigned int type; - unsigned int mode_mask; + unsigned short addr; + unsigned int type; + unsigned int mode_mask; }; struct tuner { /* device */ struct i2c_client i2c; - unsigned int type; /* chip type */ + unsigned int type; /* chip type */ - unsigned int mode; - unsigned int mode_mask; /* Combination of allowable modes */ + unsigned int mode; + unsigned int mode_mask; /* Combination of allowable modes */ - unsigned int freq; /* keep track of the current settings */ + unsigned int freq; /* keep track of the current settings */ unsigned int audmode; v4l2_std_id std; @@ -221,7 +221,7 @@ extern int tea5767_autodetection(struct i2c_client *c); #endif /* __KERNEL__ */ -#endif +#endif /* _TUNER_H */ /* * Overrides for Emacs so that we follow Linus's tabbing style. -- GitLab From 4c93b07a48039cee1d845f38294abec0f803e05e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:54 -0700 Subject: [PATCH 188/563] [PATCH] v4l: change LG TDVS H062F from NTSC to ATSC - Change LG TDVS H062F from NTSC to ATSC. Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/tuner-simple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 5e99b242a28d2..61dee53d328f5 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -242,7 +242,7 @@ static struct tunertype tuners[] = { /* see tea5767.c for details */}, { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL, 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 }, - { "LG TDVS-H062F/TUA6034", LGINNOTEK, NTSC, + { "LG TDVS-H062F/TUA6034", LGINNOTEK, ATSC, 16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732}, { "Ymec TVF66T5-B/DFF", Philips, PAL, 16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623}, -- GitLab From 08adb9e20be83bb4c5322bf15b966c537038f6d9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:55 -0700 Subject: [PATCH 189/563] [PATCH] v4l: some error treatment implemented at resume functions. - Some error treatment implemented at resume functions. Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/bttv-driver.c | 18 ++++++++++++++++-- drivers/media/video/cx88/cx88-mpeg.c | 20 +++++++++++++++++--- drivers/media/video/cx88/cx88-video.c | 20 ++++++++++++++++++-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 53ecdbf462226..b35c586a22507 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -4111,15 +4111,29 @@ static int bttv_resume(struct pci_dev *pci_dev) { struct bttv *btv = pci_get_drvdata(pci_dev); unsigned long flags; + int err; dprintk("bttv%d: resume\n", btv->c.nr); /* restore pci state */ if (btv->state.disabled) { - pci_enable_device(pci_dev); + err=pci_enable_device(pci_dev); + if (err) { + printk(KERN_WARNING "bttv%d: Can't enable device.\n", + btv->c.nr); + return err; + } btv->state.disabled = 0; } - pci_set_power_state(pci_dev, PCI_D0); + err=pci_set_power_state(pci_dev, PCI_D0); + if (err) { + pci_disable_device(pci_dev); + printk(KERN_WARNING "bttv%d: Can't enable device.\n", + btv->c.nr); + btv->state.disabled = 1; + return err; + } + pci_restore_state(pci_dev); /* restore bt878 state */ diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 6d0d15c3a1c65..ee2300e1ae0b7 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -455,14 +455,28 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) int cx8802_resume_common(struct pci_dev *pci_dev) { - struct cx8802_dev *dev = pci_get_drvdata(pci_dev); + struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; + int err; if (dev->state.disabled) { - pci_enable_device(pci_dev); + err=pci_enable_device(pci_dev); + if (err) { + printk(KERN_ERR "%s: can't enable device\n", + dev->core->name); + return err; + } dev->state.disabled = 0; } - pci_set_power_state(pci_dev, PCI_D0); + err=pci_set_power_state(pci_dev, PCI_D0); + if (err) { + printk(KERN_ERR "%s: can't enable device\n", + dev->core->name); + pci_disable_device(pci_dev); + dev->state.disabled = 1; + + return err; + } pci_restore_state(pci_dev); /* FIXME: re-initialize hardware */ diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 61d4b29ec3026..3dbc074fb515a 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -2005,12 +2005,28 @@ static int cx8800_resume(struct pci_dev *pci_dev) { struct cx8800_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; + int err; if (dev->state.disabled) { - pci_enable_device(pci_dev); + err=pci_enable_device(pci_dev); + if (err) { + printk(KERN_ERR "%s: can't enable device\n", + core->name); + return err; + } + dev->state.disabled = 0; } - pci_set_power_state(pci_dev, PCI_D0); + err= pci_set_power_state(pci_dev, PCI_D0); + if (err) { + printk(KERN_ERR "%s: can't enable device\n", + core->name); + + pci_disable_device(pci_dev); + dev->state.disabled = 1; + + return err; + } pci_restore_state(pci_dev); /* FIXME: re-initialize hardware */ -- GitLab From 33ac6b52679743c3dbb7c7245f1df90588ee1097 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:56 -0700 Subject: [PATCH 190/563] [PATCH] v4l: the Microtune 4049FM5 uses an IF frequency of 33.3 MHz for FM radio. - The Microtune 4049FM5 uses an IF frequency of 33.3 MHz for FM radio. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/bttv-cards.c | 4 ++-- drivers/media/video/tuner-simple.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 64785d3fe838e..10ab12ba4c6d9 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -299,8 +299,8 @@ static struct CARD { { 0x00011822, BTTV_TWINHAN_DST, "Twinhan VisionPlus DVB" }, { 0xfc00270f, BTTV_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, { 0x07711461, BTTV_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, - { 0xdb1018ac, BTTV_DVICO_DVBT_LITE, "DVICO FusionHDTV DVB-T Lite" }, - { 0xd50018ac, BTTV_DVICO_FUSIONHDTV_5_LITE, "DVICO FusionHDTV 5 Lite" }, + { 0xdb1018ac, BTTV_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, + { 0xd50018ac, BTTV_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, { 0, -1, NULL } }; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 61dee53d328f5..8edd73abe1d8c 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -468,6 +468,10 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) case TUNER_LG_PAL_FM: buffer[3] = 0xa5; break; + case TUNER_MICROTUNE_4049FM5: + div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ + buffer[3] = 0xa4; + break; default: buffer[3] = 0xa4; break; -- GitLab From fccdf1bd362452d5e2bc0a1874b2b504b481e367 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:57 -0700 Subject: [PATCH 191/563] [PATCH] v4l: #include <linux/config.h> no longer needed. - #include <linux/config.h> no longer needed. Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/saa7134/saa7134-dvb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index fa29dd5f7f04c..639ae51a052da 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -28,7 +28,6 @@ #include <linux/delay.h> #include <linux/kthread.h> #include <linux/suspend.h> -#include <linux/config.h> #include "saa7134-reg.h" -- GitLab From 6a989d7328aa4a0b4793ea05b13871bf1b500b1e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:57 -0700 Subject: [PATCH 192/563] [PATCH] v4l: correct the amux for composite and s-video inputs on the Sabrent SBT-TVFM card. - correct the amux for composite and s-video inputs on the Sabrent SBT-TVFM card. Signed-off-by: Michael Rodriquez-Torrent <mike@themikecam.com> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/saa7134/saa7134-cards.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 07d3ee0ada7d0..acc7a4335e230 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1372,7 +1372,7 @@ struct saa7134_board saa7134_boards[] = { .inputs = {{ .name = name_comp1, .vmux = 1, - .amux = LINE2, + .amux = LINE1, },{ .name = name_tv, .vmux = 3, @@ -1381,7 +1381,7 @@ struct saa7134_board saa7134_boards[] = { },{ .name = name_svideo, .vmux = 8, - .amux = LINE2, + .amux = LINE1, }}, .radio = { .name = name_radio, -- GitLab From 21d4df375be2c9e5f1002800036fbfb793cf031f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:03:59 -0700 Subject: [PATCH 193/563] [PATCH] v4l: print warning if pal= or secam= argument is unrecognized - print warning if pal= or secam= argument is unrecognized Signed-off-by: Philip Rowlands <phr@doc.ic.ac.uk> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/tda9887.c | 13 +++++++++++++ drivers/media/video/tuner-core.c | 12 ++++++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 79e0bd1aa70f3..0456dda2624dd 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -23,6 +23,7 @@ TDA9887 (world), TDA9885 (USA) Note: OP2 of tda988x must be set to 1, else MT2032 is disabled! - KNC One TV-Station RDS (saa7134) + - Hauppauge PVR-150/500 (possibly more) */ @@ -519,6 +520,12 @@ static int tda9887_fixup_std(struct tda9887 *t) dprintk(PREFIX "insmod fixup: PAL => PAL-DK\n"); t->std = V4L2_STD_PAL_DK; break; + case '-': + /* default parameter, do nothing */ + break; + default: + printk(PREFIX "pal= argument not recognised\n"); + break; } } if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { @@ -535,6 +542,12 @@ static int tda9887_fixup_std(struct tda9887 *t) dprintk(PREFIX "insmod fixup: SECAM => SECAM-L\n"); t->std = V4L2_STD_SECAM_L; break; + case '-': + /* default parameter, do nothing */ + break; + default: + printk(PREFIX "secam= argument not recognised\n"); + break; } } return 0; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index afc96bbb1c118..05572020af4d0 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -281,6 +281,12 @@ static int tuner_fixup_std(struct tuner *t) tuner_dbg ("insmod fixup: PAL => PAL-N\n"); t->std = V4L2_STD_PAL_N; break; + case '-': + /* default parameter, do nothing */ + break; + default: + tuner_warn ("pal= argument not recognised\n"); + break; } } if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { @@ -297,6 +303,12 @@ static int tuner_fixup_std(struct tuner *t) tuner_dbg ("insmod fixup: SECAM => SECAM-L\n"); t->std = V4L2_STD_SECAM_L; break; + case '-': + /* default parameter, do nothing */ + break; + default: + tuner_warn ("secam= argument not recognised\n"); + break; } } -- GitLab From 5129b1589883d6eaa54886f3e0c5d918dafe329e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:04:00 -0700 Subject: [PATCH 194/563] [PATCH] v4l: add some missing parameter descriptions in msp3400.c - added some missing parameter descriptions at msp3400.c Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/msp3400.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 01d567cf5c680..f0d43fc2632f3 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -124,10 +124,14 @@ module_param(standard, int, 0644); module_param(amsound, int, 0644); module_param(dolby, int, 0644); +MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Simple, 2=Simpler"); MODULE_PARM_DESC(once, "No continuous stereo monitoring"); MODULE_PARM_DESC(debug, "Enable debug messages"); +MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); +MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); + MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); MODULE_AUTHOR("Gerd Knorr"); -- GitLab From 67e49a1abe3e9458c7ffba66775b350b5ceffae0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:04:00 -0700 Subject: [PATCH 195/563] [PATCH] v4l: make the input event device for IR matchable by udev rules. - Makes the input event device created by the V4L drivers for the infrared remote matchable by udev rules. Signed-off-by: Rudo Thomas <rudo@matfyz.cz> Signed-off-by: Michael Fair <michael@daclubhouse.net> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/cx88/cx88-input.c | 1 + drivers/media/video/ir-kbd-gpio.c | 1 + drivers/media/video/saa7134/saa7134-input.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index d7980c51478d3..d81b21d6e05d0 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -445,6 +445,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->input.id.vendor = pci->vendor; ir->input.id.product = pci->device; } + ir->input.dev = &pci->dev; /* record handles to ourself */ ir->core = core; diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c index eddadc76e11d6..cf292da8fdd57 100644 --- a/drivers/media/video/ir-kbd-gpio.c +++ b/drivers/media/video/ir-kbd-gpio.c @@ -353,6 +353,7 @@ static int ir_probe(struct device *dev) ir->input.id.vendor = sub->core->pci->vendor; ir->input.id.product = sub->core->pci->device; } + ir->input.dev = &sub->core->pci->dev; if (ir->polling) { INIT_WORK(&ir->work, ir_work, ir); diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 0e97b1eec20ef..1f456c4d76f2d 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -564,6 +564,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) ir->dev.id.vendor = dev->pci->vendor; ir->dev.id.product = dev->pci->device; } + ir->dev.dev = &dev->pci->dev; /* all done */ dev->remote = ir; -- GitLab From 10b89ee387fd6cc38532a881f64b3d35f338ea0b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:04:03 -0700 Subject: [PATCH 196/563] [PATCH] v4l: include saa6588 compiler option and files / fixes comments on tuner.h - Include saa6588 compiler option and files. - Fix comment on tuner.h - linux/utsname.h replaced by linux/version.h to compile on vanilla 2.6.13 Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/Kconfig | 12 + drivers/media/video/Makefile | 2 + drivers/media/video/bttvp.h | 2 +- drivers/media/video/cx88/cx88.h | 2 +- drivers/media/video/rds.h | 48 +++ drivers/media/video/saa6588.c | 534 ++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134.h | 2 +- include/media/tuner.h | 2 +- 8 files changed, 600 insertions(+), 4 deletions(-) create mode 100644 drivers/media/video/rds.h create mode 100644 drivers/media/video/saa6588.c diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 077720c2b640b..93570355819ae 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -25,6 +25,18 @@ config VIDEO_BT848 To compile this driver as a module, choose M here: the module will be called bttv. +config VIDEO_SAA6588 + tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards" + depends on VIDEO_DEV && I2C && VIDEO_BT848 + + help + Support for Radio Data System (RDS) decoder. This allows seeing + radio station identification transmitted using this standard. + Currentlly, it works only with bt8x8 chips. + + To compile this driver as a module, choose M here: the + module will be called saa6588. + config VIDEO_PMS tristate "Mediavision Pro Movie Studio Video For Linux" depends on VIDEO_DEV && ISA diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 3e6f5347da21e..046b82de92859 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -5,6 +5,7 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o +rds-objs := saa6588.o zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o @@ -15,6 +16,7 @@ obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o obj-$(CONFIG_VIDEO_ZR36120) += zoran.o +obj-$(CONFIG_VIDEO_SAA6588) += rds.o obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index a0eb0ce1aa96b..9b0b7ca035f8a 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -25,7 +25,7 @@ #ifndef _BTTVP_H_ #define _BTTVP_H_ -#include <linux/utsname.h> +#include <linux/version.h> #define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16) #include <linux/types.h> diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 13b8fb7e921a2..f48dd43535688 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -34,7 +34,7 @@ #include "btcx-risc.h" #include "cx88-reg.h" -#include <linux/utsname.h> +#include <linux/version.h> #define CX88_VERSION_CODE KERNEL_VERSION(0,0,5) #ifndef TRUE diff --git a/drivers/media/video/rds.h b/drivers/media/video/rds.h new file mode 100644 index 0000000000000..30337d0f1a87d --- /dev/null +++ b/drivers/media/video/rds.h @@ -0,0 +1,48 @@ +/* + + Types and defines needed for RDS. This is included by + saa6588.c and every driver (e.g. bttv-driver.c) that wants + to use the saa6588 module. + + Instead of having a seperate rds.h, I'd prefer to include + this stuff in one of the already existing files like tuner.h + + (c) 2005 by Hans J. Koch + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef _RDS_H +#define _RDS_H + +struct rds_command { + unsigned int block_count; + int result; + unsigned char *buffer; + struct file *instance; + poll_table *event_list; +}; + +#define RDS_CMD_OPEN _IOW('R',1,int) +#define RDS_CMD_CLOSE _IOW('R',2,int) +#define RDS_CMD_READ _IOR('R',3,int) +#define RDS_CMD_POLL _IOR('R',4,int) + +#endif + + + + diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c new file mode 100644 index 0000000000000..1a657a70ff43c --- /dev/null +++ b/drivers/media/video/saa6588.c @@ -0,0 +1,534 @@ +/* + Driver for SAA6588 RDS decoder + + (c) 2005 Hans J. Koch + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/types.h> +#include <linux/videodev.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/wait.h> +#include <asm/uaccess.h> + +#include <media/id.h> + +#include "rds.h" + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { + 0x20 >> 1, + 0x22 >> 1, + I2C_CLIENT_END, +}; + +I2C_CLIENT_INSMOD; + +/* insmod options */ +static unsigned int debug = 0; +static unsigned int xtal = 0; +static unsigned int rbds = 0; +static unsigned int plvl = 0; +static unsigned int bufblocks = 100; + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "enable debug messages"); +MODULE_PARM(xtal, "i"); +MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0"); +MODULE_PARM(rbds, "i"); +MODULE_PARM_DESC(rbds, "select mode, 0=RDS, 1=RBDS, default 0"); +MODULE_PARM(plvl, "i"); +MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0"); +MODULE_PARM(bufblocks, "i"); +MODULE_PARM_DESC(bufblocks, "number of buffered blocks, default 100"); + +MODULE_DESCRIPTION("v4l2 driver module for SAA6588 RDS decoder"); +MODULE_AUTHOR("Hans J. Koch <koch@hjk-az.de>"); + +MODULE_LICENSE("GPL"); + +/* ---------------------------------------------------------------------- */ + +#define UNSET (-1U) +#define PREFIX "saa6588: " +#define dprintk if (debug) printk + +struct saa6588 { + struct i2c_client client; + struct work_struct work; + struct timer_list timer; + spinlock_t lock; + unsigned char *buffer; + unsigned int buf_size; + unsigned int rd_index; + unsigned int wr_index; + unsigned int block_count; + unsigned char last_blocknum; + wait_queue_head_t read_queue; + int data_available_for_read; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +/* ---------------------------------------------------------------------- */ + +/* + * SAA6588 defines + */ + +/* Initialization and mode control byte (0w) */ + +/* bit 0+1 (DAC0/DAC1) */ +#define cModeStandard 0x00 +#define cModeFastPI 0x01 +#define cModeReducedRequest 0x02 +#define cModeInvalid 0x03 + +/* bit 2 (RBDS) */ +#define cProcessingModeRDS 0x00 +#define cProcessingModeRBDS 0x04 + +/* bit 3+4 (SYM0/SYM1) */ +#define cErrCorrectionNone 0x00 +#define cErrCorrection2Bits 0x08 +#define cErrCorrection5Bits 0x10 +#define cErrCorrectionNoneRBDS 0x18 + +/* bit 5 (NWSY) */ +#define cSyncNormal 0x00 +#define cSyncRestart 0x20 + +/* bit 6 (TSQD) */ +#define cSigQualityDetectOFF 0x00 +#define cSigQualityDetectON 0x40 + +/* bit 7 (SQCM) */ +#define cSigQualityTriggered 0x00 +#define cSigQualityContinous 0x80 + +/* Pause level and flywheel control byte (1w) */ + +/* bits 0..5 (FEB0..FEB5) */ +#define cFlywheelMaxBlocksMask 0x3F +#define cFlywheelDefault 0x20 + +/* bits 6+7 (PL0/PL1) */ +#define cPauseLevel_11mV 0x00 +#define cPauseLevel_17mV 0x40 +#define cPauseLevel_27mV 0x80 +#define cPauseLevel_43mV 0xC0 + +/* Pause time/oscillator frequency/quality detector control byte (1w) */ + +/* bits 0..4 (SQS0..SQS4) */ +#define cQualityDetectSensMask 0x1F +#define cQualityDetectDefault 0x0F + +/* bit 5 (SOSC) */ +#define cSelectOscFreqOFF 0x00 +#define cSelectOscFreqON 0x20 + +/* bit 6+7 (PTF0/PTF1) */ +#define cOscFreq_4332kHz 0x00 +#define cOscFreq_8664kHz 0x40 +#define cOscFreq_12996kHz 0x80 +#define cOscFreq_17328kHz 0xC0 + +/* ---------------------------------------------------------------------- */ + +static int block_to_user_buf(struct saa6588 *s, unsigned char *user_buf) +{ + int i; + + if (s->rd_index == s->wr_index) { + if (debug > 2) + dprintk(PREFIX "Read: buffer empty.\n"); + return 0; + } + + if (debug > 2) { + dprintk(PREFIX "Read: "); + for (i = s->rd_index; i < s->rd_index + 3; i++) + dprintk("0x%02x ", s->buffer[i]); + } + + if (copy_to_user(user_buf, &s->buffer[s->rd_index], 3)) + return -EFAULT; + + s->rd_index += 3; + if (s->rd_index >= s->buf_size) + s->rd_index = 0; + s->block_count--; + + if (debug > 2) + dprintk("%d blocks total.\n", s->block_count); + + return 1; +} + +static void read_from_buf(struct saa6588 *s, struct rds_command *a) +{ + unsigned long flags; + + unsigned char *buf_ptr = a->buffer; /* This is a user space buffer! */ + unsigned int i; + unsigned int rd_blocks; + + a->result = 0; + if (!a->buffer) + return; + + while (!s->data_available_for_read) { + int ret = wait_event_interruptible(s->read_queue, + s->data_available_for_read); + if (ret == -ERESTARTSYS) { + a->result = -EINTR; + return; + } + } + + spin_lock_irqsave(&s->lock, flags); + rd_blocks = a->block_count; + if (rd_blocks > s->block_count) + rd_blocks = s->block_count; + + if (!rd_blocks) + return; + + for (i = 0; i < rd_blocks; i++) { + if (block_to_user_buf(s, buf_ptr)) { + buf_ptr += 3; + a->result++; + } else + break; + } + a->result *= 3; + s->data_available_for_read = (s->block_count > 0); + spin_unlock_irqrestore(&s->lock, flags); +} + +static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf) +{ + unsigned int i; + + if (debug > 3) + dprintk(PREFIX "New block: "); + + for (i = 0; i < 3; ++i) { + if (debug > 3) + dprintk("0x%02x ", blockbuf[i]); + s->buffer[s->wr_index] = blockbuf[i]; + s->wr_index++; + } + + if (s->wr_index >= s->buf_size) + s->wr_index = 0; + + if (s->wr_index == s->rd_index) { + s->rd_index++; + if (s->rd_index >= s->buf_size) + s->rd_index = 0; + } else + s->block_count++; + + if (debug > 3) + dprintk("%d blocks total.\n", s->block_count); +} + +static void saa6588_i2c_poll(struct saa6588 *s) +{ + unsigned long flags; + unsigned char tmpbuf[6]; + unsigned char blocknum; + unsigned char tmp; + + /* Although we only need 3 bytes, we have to read at least 6. + SAA6588 returns garbage otherwise */ + if (6 != i2c_master_recv(&s->client, &tmpbuf[0], 6)) { + if (debug > 1) + dprintk(PREFIX "read error!\n"); + return; + } + + blocknum = tmpbuf[0] >> 5; + if (blocknum == s->last_blocknum) { + if (debug > 3) + dprintk("Saw block %d again.\n", blocknum); + return; + } + + s->last_blocknum = blocknum; + + /* + Byte order according to v4l2 specification: + + Byte 0: Least Significant Byte of RDS Block + Byte 1: Most Significant Byte of RDS Block + Byte 2 Bit 7: Error bit. Indicates that an uncorrectable error + occurred during reception of this block. + Bit 6: Corrected bit. Indicates that an error was + corrected for this data block. + Bits 5-3: Received Offset. Indicates the offset received + by the sync system. + Bits 2-0: Offset Name. Indicates the offset applied to this data. + + SAA6588 byte order is Status-MSB-LSB, so we have to swap the + first and the last of the 3 bytes block. + */ + + tmp = tmpbuf[2]; + tmpbuf[2] = tmpbuf[0]; + tmpbuf[0] = tmp; + + tmp = blocknum; + tmp |= blocknum << 3; /* Received offset == Offset Name (OK ?) */ + if ((tmpbuf[2] & 0x03) == 0x03) + tmp |= 0x80; /* uncorrectable error */ + else if ((tmpbuf[2] & 0x03) != 0x00) + tmp |= 0x40; /* corrected error */ + tmpbuf[2] = tmp; /* Is this enough ? Should we also check other bits ? */ + + spin_lock_irqsave(&s->lock, flags); + block_to_buf(s, tmpbuf); + spin_unlock_irqrestore(&s->lock, flags); + s->data_available_for_read = 1; + wake_up_interruptible(&s->read_queue); +} + +static void saa6588_timer(unsigned long data) +{ + struct saa6588 *s = (struct saa6588 *)data; + + schedule_work(&s->work); +} + +static void saa6588_work(void *data) +{ + struct saa6588 *s = (struct saa6588 *)data; + + saa6588_i2c_poll(s); + mod_timer(&s->timer, jiffies + HZ / 50); /* 20 msec */ +} + +static int saa6588_configure(struct saa6588 *s) +{ + unsigned char buf[3]; + int rc; + + buf[0] = cSyncRestart; + if (rbds) + buf[0] |= cProcessingModeRBDS; + + buf[1] = cFlywheelDefault; + switch (plvl) { + case 0: + buf[1] |= cPauseLevel_11mV; + break; + case 1: + buf[1] |= cPauseLevel_17mV; + break; + case 2: + buf[1] |= cPauseLevel_27mV; + break; + case 3: + buf[1] |= cPauseLevel_43mV; + break; + default: /* nothing */ + break; + } + + buf[2] = cQualityDetectDefault | cSelectOscFreqON; + + switch (xtal) { + case 0: + buf[2] |= cOscFreq_4332kHz; + break; + case 1: + buf[2] |= cOscFreq_8664kHz; + break; + case 2: + buf[2] |= cOscFreq_12996kHz; + break; + case 3: + buf[2] |= cOscFreq_17328kHz; + break; + default: /* nothing */ + break; + } + + dprintk(PREFIX "writing: 0w=0x%02x 1w=0x%02x 2w=0x%02x\n", + buf[0], buf[1], buf[2]); + + if (3 != (rc = i2c_master_send(&s->client, buf, 3))) + printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc); + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind) +{ + struct saa6588 *s; + client_template.adapter = adap; + client_template.addr = addr; + + printk(PREFIX "chip found @ 0x%x\n", addr << 1); + + if (NULL == (s = kmalloc(sizeof(*s), GFP_KERNEL))) + return -ENOMEM; + + s->buf_size = bufblocks * 3; + + if (NULL == (s->buffer = kmalloc(s->buf_size, GFP_KERNEL))) { + kfree(s); + return -ENOMEM; + } + s->client = client_template; + s->block_count = 0; + s->wr_index = 0; + s->rd_index = 0; + s->last_blocknum = 0xff; + init_waitqueue_head(&s->read_queue); + s->data_available_for_read = 0; + i2c_set_clientdata(&s->client, s); + i2c_attach_client(&s->client); + + saa6588_configure(s); + + /* start polling via eventd */ + INIT_WORK(&s->work, saa6588_work, s); + init_timer(&s->timer); + s->timer.function = saa6588_timer; + s->timer.data = (unsigned long)s; + schedule_work(&s->work); + + return 0; +} + +static int saa6588_probe(struct i2c_adapter *adap) +{ +#ifdef I2C_CLASS_TV_ANALOG + if (adap->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adap, &addr_data, saa6588_attach); +#else + switch (adap->id) { + case I2C_ALGO_BIT | I2C_HW_B_BT848: + case I2C_ALGO_BIT | I2C_HW_B_RIVA: + case I2C_ALGO_SAA7134: + return i2c_probe(adap, &addr_data, saa6588_attach); + break; + } +#endif + return 0; +} + +static int saa6588_detach(struct i2c_client *client) +{ + struct saa6588 *s = i2c_get_clientdata(client); + + del_timer_sync(&s->timer); + flush_scheduled_work(); + + i2c_detach_client(client); + kfree(s->buffer); + kfree(s); + return 0; +} + +static int saa6588_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct saa6588 *s = i2c_get_clientdata(client); + struct rds_command *a = (struct rds_command *)arg; + + switch (cmd) { + /* --- open() for /dev/radio --- */ + case RDS_CMD_OPEN: + a->result = 0; /* return error if chip doesn't work ??? */ + break; + /* --- close() for /dev/radio --- */ + case RDS_CMD_CLOSE: + s->data_available_for_read = 1; + wake_up_interruptible(&s->read_queue); + a->result = 0; + break; + /* --- read() for /dev/radio --- */ + case RDS_CMD_READ: + read_from_buf(s, a); + break; + /* --- poll() for /dev/radio --- */ + case RDS_CMD_POLL: + a->result = 0; + if (s->data_available_for_read) { + a->result |= POLLIN | POLLRDNORM; + } + poll_wait(a->instance, &s->read_queue, a->event_list); + break; + + default: + /* nothing */ + break; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver driver = { + .owner = THIS_MODULE, + .name = "i2c saa6588 driver", + .id = -1, /* FIXME */ + .flags = I2C_DF_NOTIFY, + .attach_adapter = saa6588_probe, + .detach_client = saa6588_detach, + .command = saa6588_command, +}; + +static struct i2c_client client_template = { + .name = "saa6588", + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &driver, +}; + +static int __init saa6588_init_module(void) +{ + return i2c_add_driver(&driver); +} + +static void __exit saa6588_cleanup_module(void) +{ + i2c_del_driver(&driver); +} + +module_init(saa6588_init_module); +module_exit(saa6588_cleanup_module); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 1d70f3415e907..3ea09142ec9c4 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -19,7 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/utsname.h> +#include <linux/version.h> #define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,14) #include <linux/pci.h> diff --git a/include/media/tuner.h b/include/media/tuner.h index 5b01ee6b08685..4ad08e24a1aa2 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -1,4 +1,4 @@ - * +/* tuner.h - definition for different tuners Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de) -- GitLab From dc75fc1b924ccf44ca9f0446701acc0081605b49 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:04:04 -0700 Subject: [PATCH 197/563] [PATCH] v4l: Remove kernel version dependency from tea575x-tuner.h - Removed kernel version dependency from tea575x-tuner.h Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/sound/tea575x-tuner.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/sound/tea575x-tuner.h b/include/sound/tea575x-tuner.h index ad3c3be33c039..b82e408e758f4 100644 --- a/include/sound/tea575x-tuner.h +++ b/include/sound/tea575x-tuner.h @@ -34,9 +34,7 @@ struct snd_tea575x_ops { struct snd_tea575x { snd_card_t *card; struct video_device vd; /* video device */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) struct file_operations fops; -#endif int dev_nr; /* requested device number + 1 */ int vd_registered; /* video device is registered */ int tea5759; /* 5759 chip is present */ -- GitLab From 18fc59e230bbda9725736f8f526ef88aab212348 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:04:05 -0700 Subject: [PATCH 198/563] [PATCH] v4l: TVaudio cleanup and better debug messages - adds the adapter number + i2c address to printk msgs. - Some CodingStyle cleanups. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/tvaudio.c | 206 ++++++++++++++++++---------------- 1 file changed, 112 insertions(+), 94 deletions(-) diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 258724b2d6d21..1c31ef52f8639 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -46,7 +46,17 @@ MODULE_AUTHOR("Eric Sandeen, Steve VanDeBogart, Greg Alexander, Gerd Knorr"); MODULE_LICENSE("GPL"); #define UNSET (-1U) -#define dprintk if (debug) printk + +#define tvaudio_info(fmt, arg...) do {\ + printk(KERN_INFO "tvaudio %d-%04x: " fmt, \ + chip->c.adapter->nr, chip->c.addr , ##arg); } while (0) +#define tvaudio_warn(fmt, arg...) do {\ + printk(KERN_WARNING "tvaudio %d-%04x: " fmt, \ + chip->c.adapter->nr, chip->c.addr , ##arg); } while (0) +#define tvaudio_dbg(fmt, arg...) do {\ + if (debug) \ + printk(KERN_INFO "tvaudio %d-%04x: " fmt, \ + chip->c.adapter->nr, chip->c.addr , ##arg); } while (0) /* ---------------------------------------------------------------------- */ /* our structs */ @@ -162,23 +172,24 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) unsigned char buffer[2]; if (-1 == subaddr) { - dprintk("%s: chip_write: 0x%x\n", chip->c.name, val); + tvaudio_dbg("%s: chip_write: 0x%x\n", + chip->c.name, val); chip->shadow.bytes[1] = val; buffer[0] = val; if (1 != i2c_master_send(&chip->c,buffer,1)) { - printk(KERN_WARNING "%s: I/O error (write 0x%x)\n", - chip->c.name, val); + tvaudio_warn("%s: I/O error (write 0x%x)\n", + chip->c.name, val); return -1; } } else { - dprintk("%s: chip_write: reg%d=0x%x\n", + tvaudio_dbg("%s: chip_write: reg%d=0x%x\n", chip->c.name, subaddr, val); chip->shadow.bytes[subaddr+1] = val; buffer[0] = subaddr; buffer[1] = val; if (2 != i2c_master_send(&chip->c,buffer,2)) { - printk(KERN_WARNING "%s: I/O error (write reg%d=0x%x)\n", - chip->c.name, subaddr, val); + tvaudio_warn("%s: I/O error (write reg%d=0x%x)\n", + chip->c.name, subaddr, val); return -1; } } @@ -202,29 +213,30 @@ static int chip_read(struct CHIPSTATE *chip) unsigned char buffer; if (1 != i2c_master_recv(&chip->c,&buffer,1)) { - printk(KERN_WARNING "%s: I/O error (read)\n", chip->c.name); + tvaudio_warn("%s: I/O error (read)\n", + chip->c.name); return -1; } - dprintk("%s: chip_read: 0x%x\n", chip->c.name, buffer); + tvaudio_dbg("%s: chip_read: 0x%x\n",chip->c.name,buffer); return buffer; } static int chip_read2(struct CHIPSTATE *chip, int subaddr) { - unsigned char write[1]; - unsigned char read[1]; - struct i2c_msg msgs[2] = { - { chip->c.addr, 0, 1, write }, - { chip->c.addr, I2C_M_RD, 1, read } - }; - write[0] = subaddr; + unsigned char write[1]; + unsigned char read[1]; + struct i2c_msg msgs[2] = { + { chip->c.addr, 0, 1, write }, + { chip->c.addr, I2C_M_RD, 1, read } + }; + write[0] = subaddr; if (2 != i2c_transfer(chip->c.adapter,msgs,2)) { - printk(KERN_WARNING "%s: I/O error (read2)\n", chip->c.name); + tvaudio_warn("%s: I/O error (read2)\n", chip->c.name); return -1; } - dprintk("%s: chip_read2: reg%d=0x%x\n", - chip->c.name, subaddr, read[0]); + tvaudio_dbg("%s: chip_read2: reg%d=0x%x\n", + chip->c.name,subaddr,read[0]); return read[0]; } @@ -236,17 +248,19 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) return 0; /* update our shadow register set; print bytes if (debug > 0) */ - dprintk("%s: chip_cmd(%s): reg=%d, data:", - chip->c.name, name, cmd->bytes[0]); + tvaudio_dbg("%s: chip_cmd(%s): reg=%d, data:", + chip->c.name,name,cmd->bytes[0]); for (i = 1; i < cmd->count; i++) { - dprintk(" 0x%x",cmd->bytes[i]); + if (debug) + printk(" 0x%x",cmd->bytes[i]); chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i]; } - dprintk("\n"); + if (debug) + printk("\n"); /* send data to the chip */ if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) { - printk(KERN_WARNING "%s: I/O error (%s)\n", chip->c.name, name); + tvaudio_warn("%s: I/O error (%s)\n", chip->c.name, name); return -1; } return 0; @@ -261,19 +275,19 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) static void chip_thread_wake(unsigned long data) { - struct CHIPSTATE *chip = (struct CHIPSTATE*)data; + struct CHIPSTATE *chip = (struct CHIPSTATE*)data; wake_up_interruptible(&chip->wq); } static int chip_thread(void *data) { DECLARE_WAITQUEUE(wait, current); - struct CHIPSTATE *chip = data; + struct CHIPSTATE *chip = data; struct CHIPDESC *desc = chiplist + chip->type; daemonize("%s", chip->c.name); allow_signal(SIGTERM); - dprintk("%s: thread started\n", chip->c.name); + tvaudio_dbg("%s: thread started\n", chip->c.name); for (;;) { add_wait_queue(&chip->wq, &wait); @@ -285,7 +299,7 @@ static int chip_thread(void *data) try_to_freeze(); if (chip->done || signal_pending(current)) break; - dprintk("%s: thread wakeup\n", chip->c.name); + tvaudio_dbg("%s: thread wakeup\n", chip->c.name); /* don't do anything for radio or if mode != auto */ if (chip->norm == VIDEO_MODE_RADIO || chip->mode != 0) @@ -298,8 +312,8 @@ static int chip_thread(void *data) mod_timer(&chip->wt, jiffies+2*HZ); } - dprintk("%s: thread exiting\n", chip->c.name); - complete_and_exit(&chip->texit, 0); + tvaudio_dbg("%s: thread exiting\n", chip->c.name); + complete_and_exit(&chip->texit, 0); return 0; } @@ -309,9 +323,9 @@ static void generic_checkmode(struct CHIPSTATE *chip) int mode = desc->getmode(chip); if (mode == chip->prevmode) - return; + return; - dprintk("%s: thread checkmode\n", chip->c.name); + tvaudio_dbg("%s: thread checkmode\n", chip->c.name); chip->prevmode = mode; if (mode & VIDEO_SOUND_STEREO) @@ -358,8 +372,8 @@ static int tda9840_getmode(struct CHIPSTATE *chip) if (val & TDA9840_ST_STEREO) mode |= VIDEO_SOUND_STEREO; - dprintk ("tda9840_getmode(): raw chip read: %d, return: %d\n", - val, mode); + tvaudio_dbg ("tda9840_getmode(): raw chip read: %d, return: %d\n", + val, mode); return mode; } @@ -654,8 +668,8 @@ static int tda9873_getmode(struct CHIPSTATE *chip) mode |= VIDEO_SOUND_STEREO; if (val & TDA9873_DUAL) mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - dprintk ("tda9873_getmode(): raw chip read: %d, return: %d\n", - val, mode); + tvaudio_dbg ("tda9873_getmode(): raw chip read: %d, return: %d\n", + val, mode); return mode; } @@ -665,12 +679,12 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) { - dprintk("tda9873_setmode(): external input\n"); + tvaudio_dbg("tda9873_setmode(): external input\n"); return; } - dprintk("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); - dprintk("tda9873_setmode(): sw_data = %d\n", sw_data); + tvaudio_dbg("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); + tvaudio_dbg("tda9873_setmode(): sw_data = %d\n", sw_data); switch (mode) { case VIDEO_SOUND_MONO: @@ -691,7 +705,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) } chip_write(chip, TDA9873_SW, sw_data); - dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n", + tvaudio_dbg("tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data); } @@ -828,9 +842,9 @@ static int tda9874a_setup(struct CHIPSTATE *chip) } else { /* dic == 0x07 */ chip_write(chip, TDA9874A_AMCONR, 0xfb); chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); - chip_write(chip, TDA9874A_AOSR, 0x00); // or 0x10 + chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */ } - dprintk("tda9874a_setup(): %s [0x%02X].\n", + tvaudio_dbg("tda9874a_setup(): %s [0x%02X].\n", tda9874a_modelist[tda9874a_STD].name,tda9874a_STD); return 1; } @@ -873,7 +887,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } - dprintk("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", + tvaudio_dbg("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", dsr, nsr, necr, mode); return mode; } @@ -919,7 +933,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_AOSR, aosr); chip_write(chip, TDA9874A_MDACOSR, mdacosr); - dprintk("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", + tvaudio_dbg("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", mode, aosr, mdacosr); } else { /* dic == 0x07 */ @@ -954,7 +968,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_FMMR, fmmr); chip_write(chip, TDA9874A_AOSR, aosr); - dprintk("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", + tvaudio_dbg("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", mode, fmmr, aosr); } } @@ -968,10 +982,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip) if(-1 == (sic = chip_read2(chip,TDA9874A_SIC))) return 0; - dprintk("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); + tvaudio_dbg("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); if((dic == 0x11)||(dic == 0x07)) { - printk("tvaudio: found tda9874%s.\n", (dic == 0x11) ? "a":"h"); + tvaudio_info("found tda9874%s.\n", (dic == 0x11) ? "a":"h"); tda9874a_dic = dic; /* remember device id. */ return 1; } @@ -1146,7 +1160,7 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode) /* ---------------------------------------------------------------------- */ /* audio chip descriptions - defines+functions for TA8874Z */ -// write 1st byte +/* write 1st byte */ #define TA8874Z_LED_STE 0x80 #define TA8874Z_LED_BIL 0x40 #define TA8874Z_LED_EXT 0x20 @@ -1156,21 +1170,22 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode) #define TA8874Z_MODE_SUB 0x02 #define TA8874Z_MODE_MAIN 0x01 -// write 2nd byte -//#define TA8874Z_TI 0x80 // test mode +/* write 2nd byte */ +/*#define TA8874Z_TI 0x80 */ /* test mode */ #define TA8874Z_SEPARATION 0x3f #define TA8874Z_SEPARATION_DEFAULT 0x10 -// read +/* read */ #define TA8874Z_B1 0x80 #define TA8874Z_B0 0x40 #define TA8874Z_CHAG_FLAG 0x20 -// B1 B0 -// mono L H -// stereo L L -// BIL H L - +/* + * B1 B0 + * mono L H + * stereo L L + * BIL H L + */ static int ta8874z_getmode(struct CHIPSTATE *chip) { int val, mode; @@ -1182,7 +1197,7 @@ static int ta8874z_getmode(struct CHIPSTATE *chip) }else if (!(val & TA8874Z_B0)){ mode |= VIDEO_SOUND_STEREO; } - //dprintk ("ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); + /* tvaudio_dbg ("ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ return mode; } @@ -1195,7 +1210,7 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; audiocmd *t = NULL; - dprintk("ta8874z_setmode(): mode: 0x%02x\n", mode); + tvaudio_dbg("ta8874z_setmode(): mode: 0x%02x\n", mode); switch(mode){ case VIDEO_SOUND_MONO: @@ -1235,11 +1250,11 @@ static int tda9850 = 1; static int tda9855 = 1; static int tda9873 = 1; static int tda9874a = 1; -static int tea6300 = 0; // address clash with msp34xx -static int tea6320 = 0; // address clash with msp34xx +static int tea6300 = 0; /* address clash with msp34xx */ +static int tea6320 = 0; /* address clash with msp34xx */ static int tea6420 = 1; static int pic16c54 = 1; -static int ta8874z = 0; // address clash with tda9840 +static int ta8874z = 0; /* address clash with tda9840 */ module_param(tda8425, int, 0444); module_param(tda9840, int, 0444); @@ -1441,7 +1456,7 @@ static struct CHIPDESC chiplist[] = { { .name = "ta8874z", .id = -1, - //.id = I2C_DRIVERID_TA8874Z, + /*.id = I2C_DRIVERID_TA8874Z, */ .checkit = ta8874z_checkit, .insmodopt = &ta8874z, .addr_lo = I2C_TDA9840 >> 1, @@ -1476,7 +1491,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) i2c_set_clientdata(&chip->c, chip); /* find description for the chip */ - dprintk("tvaudio: chip found @ i2c-addr=0x%x\n", addr<<1); + tvaudio_dbg("chip found @ 0x%x\n", addr<<1); for (desc = chiplist; desc->name != NULL; desc++) { if (0 == *(desc->insmodopt)) continue; @@ -1488,17 +1503,19 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) break; } if (desc->name == NULL) { - dprintk("tvaudio: no matching chip description found\n"); + tvaudio_dbg("no matching chip description found\n"); return -EIO; } - printk("tvaudio: found %s @ 0x%x\n", desc->name, addr<<1); - dprintk("tvaudio: matches:%s%s%s.\n", - (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", - (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", - (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); + tvaudio_info("%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name); + if (desc->flags) { + tvaudio_dbg("matches:%s%s%s.\n", + (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", + (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", + (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); + } /* fill required data structures */ - strcpy(chip->c.name, desc->name); + strcpy(chip->c.name,desc->name); chip->type = desc-chiplist; chip->shadow.count = desc->registers+1; chip->prevmode = -1; @@ -1534,7 +1551,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) init_completion(&chip->texit); chip->tpid = kernel_thread(chip_thread,(void *)chip,0); if (chip->tpid < 0) - printk(KERN_WARNING "%s: kernel_thread() failed\n", + tvaudio_warn("%s: kernel_thread() failed\n", chip->c.name); wake_up_interruptible(&chip->wq); } @@ -1545,7 +1562,7 @@ static int chip_probe(struct i2c_adapter *adap) { /* don't attach on saa7146 based cards, because dedicated drivers are used */ - if (adap->id == I2C_HW_SAA7146) + if ((adap->id == I2C_HW_SAA7146)) return 0; #ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) @@ -1584,11 +1601,11 @@ static int chip_detach(struct i2c_client *client) static int chip_command(struct i2c_client *client, unsigned int cmd, void *arg) { - __u16 *sarg = arg; + __u16 *sarg = arg; struct CHIPSTATE *chip = i2c_get_clientdata(client); struct CHIPDESC *desc = chiplist + chip->type; - dprintk("%s: chip_command 0x%x\n", chip->c.name, cmd); + tvaudio_dbg("%s: chip_command 0x%x\n",chip->c.name,cmd); switch (cmd) { case AUDC_SET_INPUT: @@ -1601,7 +1618,6 @@ static int chip_command(struct i2c_client *client, break; case AUDC_SET_RADIO: - dprintk(KERN_DEBUG "tvaudio: AUDC_SET_RADIO\n"); chip->norm = VIDEO_MODE_RADIO; chip->watch_stereo = 0; /* del_timer(&chip->wt); */ @@ -1609,7 +1625,7 @@ static int chip_command(struct i2c_client *client, /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ + kernel pointer here... */ case VIDIOCGAUDIO: { struct video_audio *va = arg; @@ -1643,9 +1659,9 @@ static int chip_command(struct i2c_client *client, if (desc->flags & CHIP_HAS_VOLUME) { chip->left = (min(65536 - va->balance,32768) * - va->volume) / 32768; + va->volume) / 32768; chip->right = (min(va->balance,(__u16)32768) * - va->volume) / 32768; + va->volume) / 32768; chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); } @@ -1667,17 +1683,16 @@ static int chip_command(struct i2c_client *client, { struct video_channel *vc = arg; - dprintk(KERN_DEBUG "tvaudio: VIDIOCSCHAN\n"); chip->norm = vc->norm; break; } case VIDIOCSFREQ: { - chip->mode = 0; /* automatic */ + chip->mode = 0; /* automatic */ if (desc->checkmode) { desc->setmode(chip,VIDEO_SOUND_MONO); - if (chip->prevmode != VIDEO_SOUND_MONO) - chip->prevmode = -1; /* reset previous mode */ + if (chip->prevmode != VIDEO_SOUND_MONO) + chip->prevmode = -1; /* reset previous mode */ mod_timer(&chip->wt, jiffies+2*HZ); /* the thread will call checkmode() later */ } @@ -1689,29 +1704,32 @@ static int chip_command(struct i2c_client *client, static struct i2c_driver driver = { .owner = THIS_MODULE, - .name = "generic i2c audio driver", - .id = I2C_DRIVERID_TVAUDIO, - .flags = I2C_DF_NOTIFY, - .attach_adapter = chip_probe, - .detach_client = chip_detach, - .command = chip_command, + .name = "generic i2c audio driver", + .id = I2C_DRIVERID_TVAUDIO, + .flags = I2C_DF_NOTIFY, + .attach_adapter = chip_probe, + .detach_client = chip_detach, + .command = chip_command, }; static struct i2c_client client_template = { .name = "(unset)", .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + .driver = &driver, }; static int __init audiochip_init_module(void) { struct CHIPDESC *desc; - printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); - printk(KERN_INFO "tvaudio: known chips: "); - for (desc = chiplist; desc->name != NULL; desc++) - printk("%s%s", (desc == chiplist) ? "" : ",",desc->name); - printk("\n"); + + if (debug) { + printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); + printk(KERN_INFO "tvaudio: known chips: "); + for (desc = chiplist; desc->name != NULL; desc++) + printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); + printk("\n"); + } return i2c_add_driver(&driver); } -- GitLab From 0f97a931b337e4662e736ca67f1fab0a187f5852 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Date: Fri, 9 Sep 2005 13:04:05 -0700 Subject: [PATCH 199/563] [PATCH] v4l: tveeprom improved to support newer Hauppage cards - tveeprom improved and updated to reflect newer Hauppage cards. - CodingStyle fixes. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/media/video/bttv-cards.c | 3 +- drivers/media/video/bttv-driver.c | 1 + drivers/media/video/cx88/cx88-cards.c | 2 +- drivers/media/video/tveeprom.c | 327 ++++++++++++++++++-------- include/media/tveeprom.h | 8 +- 5 files changed, 238 insertions(+), 103 deletions(-) diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 10ab12ba4c6d9..190977a1e5494 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -3060,7 +3060,7 @@ static void __devinit hauppauge_eeprom(struct bttv *btv) { struct tveeprom tv; - tveeprom_hauppauge_analog(&tv, eeprom_data); + tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data); btv->tuner_type = tv.tuner_type; btv->has_radio = tv.has_radio; } @@ -4485,6 +4485,7 @@ void __devinit bttv_check_chipset(void) } if (UNSET != latency) printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency); + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, dev))) { unsigned char b; diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index b35c586a22507..a564321db2f02 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -4079,6 +4079,7 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) struct bttv_buffer_set idle; unsigned long flags; + dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event); /* stop dma + irqs */ spin_lock_irqsave(&btv->s_lock,flags); diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 92623231db78c..4da91d535a5b0 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -945,7 +945,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) { struct tveeprom tv; - tveeprom_hauppauge_analog(&tv, eeprom_data); + tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); core->tuner_type = tv.tuner_type; core->has_radio = tv.has_radio; } diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 367401449e3cc..5344d55921993 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -47,18 +47,21 @@ MODULE_LICENSE("GPL"); static int debug = 0; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-2)"); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown") -#define dprintk(num, args...) \ - do { \ - if (debug >= num) \ - printk(KERN_INFO "tveeprom: " args); \ - } while (0) +#define tveeprom_info(fmt, arg...) do {\ + printk(KERN_INFO "tveeprom %d-%04x: " fmt, \ + c->adapter->nr, c->addr , ##arg); } while (0) +#define tveeprom_warn(fmt, arg...) do {\ + printk(KERN_WARNING "tveeprom %d-%04x: " fmt, \ + c->adapter->nr, c->addr , ##arg); } while (0) +#define tveeprom_dbg(fmt, arg...) do {\ + if (debug) \ + printk(KERN_INFO "tveeprom %d-%04x: " fmt, \ + c->adapter->nr, c->addr , ##arg); } while (0) -#define TVEEPROM_KERN_ERR(args...) printk(KERN_ERR "tveeprom: " args); -#define TVEEPROM_KERN_INFO(args...) printk(KERN_INFO "tveeprom: " args); /* ----------------------------------------------------------------------- */ /* some hauppauge specific stuff */ @@ -70,14 +73,14 @@ static struct HAUPPAUGE_TUNER_FMT } hauppauge_tuner_fmt[] = { - { 0x00000000, "unknown1" }, - { 0x00000000, "unknown2" }, - { 0x00000007, "PAL(B/G)" }, - { 0x00001000, "NTSC(M)" }, - { 0x00000010, "PAL(I)" }, - { 0x00400000, "SECAM(L/L�)" }, - { 0x00000e00, "PAL(D/K)" }, - { 0x03000000, "ATSC Digital" }, + { 0x00000000, " unknown1" }, + { 0x00000000, " unknown2" }, + { 0x00000007, " PAL(B/G)" }, + { 0x00001000, " NTSC(M)" }, + { 0x00000010, " PAL(I)" }, + { 0x00400000, " SECAM(L/L')" }, + { 0x00000e00, " PAL(D/K)" }, + { 0x03000000, " ATSC Digital" }, }; /* This is the full list of possible tuners. Many thanks to Hauppauge for @@ -203,20 +206,47 @@ hauppauge_tuner[] = { TUNER_TCL_2002N, "TCL 2002N 5H"}, /* 100-103 */ { TUNER_ABSENT, "Unspecified"}, - { TUNER_ABSENT, "Unspecified"}, + { TUNER_TEA5767, "Philips TEA5767HN FM Radio"}, { TUNER_ABSENT, "Unspecified"}, { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05 4"}, }; -static char *sndtype[] = { - "None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C", "MSP3410D", - "MSP3415", "MSP3430", "MSP3438", "CS5331", "MSP3435", "MSP3440", - "MSP3445", "MSP3411", "MSP3416", "MSP3425", +/* This list is supplied by Hauppauge. Thanks! */ +static const char *audioIC[] = { + /* 0-4 */ + "None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C", + /* 5-9 */ + "MSP3410D", "MSP3415", "MSP3430", "MSP3438", "CS5331", + /* 10-14 */ + "MSP3435", "MSP3440", "MSP3445", "MSP3411", "MSP3416", + /* 15-19 */ + "MSP3425", "MSP3451", "MSP3418", "Type 0x12", "OKI7716", + /* 20-24 */ + "MSP4410", "MSP4420", "MSP4440", "MSP4450", "MSP4408", + /* 25-29 */ + "MSP4418", "MSP4428", "MSP4448", "MSP4458", "Type 0x1d", + /* 30-34 */ + "CX880", "CX881", "CX883", "CX882", "CX25840", + /* 35-38 */ + "CX25841", "CX25842", "CX25843", "CX23418", +}; - "Type 0x10","Type 0x11","Type 0x12","Type 0x13", - "Type 0x14","Type 0x15","Type 0x16","Type 0x17", - "Type 0x18","MSP4418","Type 0x1a","MSP4448", - "Type 0x1c","Type 0x1d","Type 0x1e","Type 0x1f", +/* This list is supplied by Hauppauge. Thanks! */ +static const char *decoderIC[] = { + /* 0-4 */ + "None", "BT815", "BT817", "BT819", "BT815A", + /* 5-9 */ + "BT817A", "BT819A", "BT827", "BT829", "BT848", + /* 10-14 */ + "BT848A", "BT849A", "BT829A", "BT827A", "BT878", + /* 15-19 */ + "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115", + /* 20-24 */ + "CX880", "CX881", "CX883", "SAA7111", "SAA7113", + /* 25-29 */ + "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842", + /* 30-31 */ + "CX25843", "CX23418", }; static int hasRadioTuner(int tunerType) @@ -257,7 +287,8 @@ static int hasRadioTuner(int tunerType) return 0; } -void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data) +void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, + unsigned char *eeprom_data) { /* ---------------------------------------------- ** The hauppauge eeprom format is tagged @@ -267,10 +298,11 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data ** if packet[0] & f8 == f8, then EOD and packet[1] == checksum ** ** In our (ivtv) case we're interested in the following: - ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) - ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt) - ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) - ** audio proc: tag [02].01 or [05].00 (lower nibble indexes lut?) + ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) + ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt) + ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) + ** audio proc: tag [02].01 or [05].00 (mask with 0x7f) + ** decoder proc: tag [09].01) ** Fun info: ** model: tag [00].07-08 or [06].00-01 @@ -280,20 +312,24 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data ** # of inputs/outputs ??? */ - int i, j, len, done, beenhere, tag, tuner = 0, t_format = 0; - char *t_name = NULL, *t_fmt_name = NULL; + int i, j, len, done, beenhere, tag; - dprintk(1, "%s\n",__FUNCTION__); - tvee->revision = done = len = beenhere = 0; - for (i = 0; !done && i < 256; i += len) { - dprintk(2, "processing pos = %02x (%02x, %02x)\n", - i, eeprom_data[i], eeprom_data[i + 1]); + int tuner1 = 0, t_format1 = 0; + char *t_name1 = NULL; + const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" }; + int tuner2 = 0, t_format2 = 0; + char *t_name2 = NULL; + const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" }; + + memset(tvee, 0, sizeof(*tvee)); + done = len = beenhere = 0; + for (i = 0; !done && i < 256; i += len) { if (eeprom_data[i] == 0x84) { len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8); - i+=3; + i += 3; } else if ((eeprom_data[i] & 0xf0) == 0x70) { - if ((eeprom_data[i] & 0x08)) { + if (eeprom_data[i] & 0x08) { /* verify checksum! */ done = 1; break; @@ -301,24 +337,30 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data len = eeprom_data[i] & 0x07; ++i; } else { - TVEEPROM_KERN_ERR("Encountered bad packet header [%02x]. " + tveeprom_warn("Encountered bad packet header [%02x]. " "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]); return; } - dprintk(1, "%3d [%02x] ", len, eeprom_data[i]); - for(j = 1; j < len; j++) { - dprintk(1, "%02x ", eeprom_data[i + j]); - } - dprintk(1, "\n"); + if (debug) { + tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1); + for(j = 1; j < len; j++) { + printk(" %02x", eeprom_data[i + j]); + } + printk("\n"); + } /* process by tag */ tag = eeprom_data[i]; switch (tag) { case 0x00: - tuner = eeprom_data[i+6]; - t_format = eeprom_data[i+5]; + /* tag: 'Comprehensive' */ + tuner1 = eeprom_data[i+6]; + t_format1 = eeprom_data[i+5]; tvee->has_radio = eeprom_data[i+len-1]; + /* old style tag, don't know how to detect + IR presence, mark as unknown. */ + tvee->has_ir = 2; tvee->model = eeprom_data[i+8] + (eeprom_data[i+9] << 8); @@ -326,25 +368,43 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data (eeprom_data[i+11] << 8) + (eeprom_data[i+12] << 16); break; + case 0x01: + /* tag: 'SerialID' */ tvee->serial_number = eeprom_data[i+6] + (eeprom_data[i+7] << 8) + (eeprom_data[i+8] << 16); break; + case 0x02: - tvee->audio_processor = eeprom_data[i+2] & 0x0f; + /* tag 'AudioInfo' + Note mask with 0x7F, high bit used on some older models + to indicate 4052 mux was removed in favor of using MSP + inputs directly. */ + tvee->audio_processor = eeprom_data[i+2] & 0x7f; break; + + /* case 0x03: tag 'EEInfo' */ + case 0x04: + /* tag 'SerialID2' */ tvee->serial_number = eeprom_data[i+5] + (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); break; + case 0x05: - tvee->audio_processor = eeprom_data[i+1] & 0x0f; + /* tag 'Audio2' + Note mask with 0x7F, high bit used on some older models + to indicate 4052 mux was removed in favor of using MSP + inputs directly. */ + tvee->audio_processor = eeprom_data[i+1] & 0x7f; break; + case 0x06: + /* tag 'ModelRev' */ tvee->model = eeprom_data[i+1] + (eeprom_data[i+2] << 8); @@ -352,27 +412,66 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); break; + + case 0x07: + /* tag 'Details': according to Hauppauge not interesting + on any PCI-era or later boards. */ + break; + + /* there is no tag 0x08 defined */ + + case 0x09: + /* tag 'Video' */ + tvee->decoder_processor = eeprom_data[i + 1]; + break; + case 0x0a: - if(beenhere == 0) { - tuner = eeprom_data[i+2]; - t_format = eeprom_data[i+1]; + /* tag 'Tuner' */ + if (beenhere == 0) { + tuner1 = eeprom_data[i+2]; + t_format1 = eeprom_data[i+1]; beenhere = 1; - break; } else { - break; - } + /* a second (radio) tuner may be present */ + tuner2 = eeprom_data[i+2]; + t_format2 = eeprom_data[i+1]; + if (t_format2 == 0) { /* not a TV tuner? */ + tvee->has_radio = 1; /* must be radio */ + } + } + break; + + case 0x0b: + /* tag 'Inputs': according to Hauppauge this is specific + to each driver family, so no good assumptions can be + made. */ + break; + + /* case 0x0c: tag 'Balun' */ + /* case 0x0d: tag 'Teletext' */ + case 0x0e: + /* tag: 'Radio' */ tvee->has_radio = eeprom_data[i+1]; break; + + case 0x0f: + /* tag 'IRInfo' */ + tvee->has_ir = eeprom_data[i+1]; + break; + + /* case 0x10: tag 'VBIInfo' */ + /* case 0x11: tag 'QCInfo' */ + /* case 0x12: tag 'InfoBits' */ + default: - dprintk(1, "Not sure what to do with tag [%02x]\n", tag); + tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag); /* dump the rest of the packet? */ } - } if (!done) { - TVEEPROM_KERN_ERR("Ran out of data!\n"); + tveeprom_warn("Ran out of data!\n"); return; } @@ -384,47 +483,72 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data tvee->rev_str[4] = 0; } - if (hasRadioTuner(tuner) && !tvee->has_radio) { - TVEEPROM_KERN_INFO("The eeprom says no radio is present, but the tuner type\n"); - TVEEPROM_KERN_INFO("indicates otherwise. I will assume that radio is present.\n"); + if (hasRadioTuner(tuner1) && !tvee->has_radio) { + tveeprom_info("The eeprom says no radio is present, but the tuner type\n"); + tveeprom_info("indicates otherwise. I will assume that radio is present.\n"); tvee->has_radio = 1; } - if (tuner < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { - tvee->tuner_type = hauppauge_tuner[tuner].id; - t_name = hauppauge_tuner[tuner].name; + if (tuner1 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { + tvee->tuner_type = hauppauge_tuner[tuner1].id; + t_name1 = hauppauge_tuner[tuner1].name; } else { - t_name = "<unknown>"; + t_name1 = "unknown"; + } + + if (tuner2 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { + tvee->tuner2_type = hauppauge_tuner[tuner2].id; + t_name2 = hauppauge_tuner[tuner2].name; + } else { + t_name2 = "unknown"; } tvee->tuner_formats = 0; - t_fmt_name = "<none>"; - for (i = 0; i < 8; i++) { - if (t_format & (1<<i)) { + tvee->tuner2_formats = 0; + for (i = j = 0; i < 8; i++) { + if (t_format1 & (1 << i)) { tvee->tuner_formats |= hauppauge_tuner_fmt[i].id; - /* yuck */ - t_fmt_name = hauppauge_tuner_fmt[i].name; + t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name; } + if (t_format2 & (1 << i)) { + tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id; + t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name; + } } - - TVEEPROM_KERN_INFO("Hauppauge: model = %d, rev = %s, serial# = %d\n", - tvee->model, - tvee->rev_str, - tvee->serial_number); - TVEEPROM_KERN_INFO("tuner = %s (idx = %d, type = %d)\n", - t_name, - tuner, - tvee->tuner_type); - TVEEPROM_KERN_INFO("tuner fmt = %s (eeprom = 0x%02x, v4l2 = 0x%08x)\n", - t_fmt_name, - t_format, - tvee->tuner_formats); - - TVEEPROM_KERN_INFO("audio_processor = %s (type = %d)\n", - STRM(sndtype,tvee->audio_processor), + tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n", + tvee->model, tvee->rev_str, tvee->serial_number); + tveeprom_info("tuner model is %s (idx %d, type %d)\n", + t_name1, tuner1, tvee->tuner_type); + tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", + t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3], + t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7], + t_format1); + if (tuner2) { + tveeprom_info("second tuner model is %s (idx %d, type %d)\n", + t_name2, tuner2, tvee->tuner2_type); + } + if (t_format2) { + tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", + t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3], + t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7], + t_format2); + } + tveeprom_info("audio processor is %s (idx %d)\n", + STRM(audioIC, tvee->audio_processor), tvee->audio_processor); - + if (tvee->decoder_processor) { + tveeprom_info("decoder processor is %s (idx %d)\n", + STRM(decoderIC, tvee->decoder_processor), + tvee->decoder_processor); + } + if (tvee->has_ir == 2) + tveeprom_info("has %sradio\n", + tvee->has_radio ? "" : "no "); + else + tveeprom_info("has %sradio, has %sIR remote\n", + tvee->has_radio ? "" : "no ", + tvee->has_ir ? "" : "no "); } EXPORT_SYMBOL(tveeprom_hauppauge_analog); @@ -436,23 +560,31 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) unsigned char buf; int err; - dprintk(1, "%s\n",__FUNCTION__); buf = 0; - if (1 != (err = i2c_master_send(c,&buf,1))) { - printk(KERN_INFO "tveeprom(%s): Huh, no eeprom present (err=%d)?\n", - c->name,err); + if (1 != (err = i2c_master_send(c, &buf, 1))) { + tveeprom_info("Huh, no eeprom present (err=%d)?\n", err); return -1; } - if (len != (err = i2c_master_recv(c,eedata,len))) { - printk(KERN_WARNING "tveeprom(%s): i2c eeprom read error (err=%d)\n", - c->name,err); + if (len != (err = i2c_master_recv(c, eedata, len))) { + tveeprom_warn("i2c eeprom read error (err=%d)\n", err); return -1; } + if (debug) { + int i; + + tveeprom_info("full 256-byte eeprom dump:\n"); + for (i = 0; i < len; i++) { + if (0 == (i % 16)) + tveeprom_info("%02x:", i); + printk(" %02x", eedata[i]); + if (15 == (i % 16)) + printk("\n"); + } + } return 0; } EXPORT_SYMBOL(tveeprom_read); - /* ----------------------------------------------------------------------- */ /* needed for ivtv.sf.net at the moment. Should go away in the long */ /* run, just call the exported tveeprom_* directly, there is no point in */ @@ -485,7 +617,7 @@ tveeprom_command(struct i2c_client *client, buf = kmalloc(256,GFP_KERNEL); memset(buf,0,256); tveeprom_read(client,buf,256); - tveeprom_hauppauge_analog(&eeprom,buf); + tveeprom_hauppauge_analog(client, &eeprom,buf); kfree(buf); eeprom_props[0] = eeprom.tuner_type; eeprom_props[1] = eeprom.tuner_formats; @@ -506,8 +638,6 @@ tveeprom_detect_client(struct i2c_adapter *adapter, { struct i2c_client *client; - dprintk(1,"%s: id 0x%x @ 0x%x\n",__FUNCTION__, - adapter->id, address << 1); client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); if (NULL == client) return -ENOMEM; @@ -524,7 +654,6 @@ tveeprom_detect_client(struct i2c_adapter *adapter, static int tveeprom_attach_adapter (struct i2c_adapter *adapter) { - dprintk(1,"%s: id 0x%x\n",__FUNCTION__,adapter->id); if (adapter->id != I2C_HW_B_BT848) return 0; return i2c_probe(adapter, &addr_data, tveeprom_detect_client); diff --git a/include/media/tveeprom.h b/include/media/tveeprom.h index e24e841c32117..e2035c7da0948 100644 --- a/include/media/tveeprom.h +++ b/include/media/tveeprom.h @@ -3,15 +3,19 @@ struct tveeprom { u32 has_radio; + u32 has_ir; /* 0: no IR, 1: IR present, 2: unknown */ u32 tuner_type; u32 tuner_formats; + u32 tuner2_type; + u32 tuner2_formats; + u32 digitizer; u32 digitizer_formats; u32 audio_processor; - /* a_p_fmts? */ + u32 decoder_processor; u32 model; u32 revision; @@ -19,7 +23,7 @@ struct tveeprom { char rev_str[5]; }; -void tveeprom_hauppauge_analog(struct tveeprom *tvee, +void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, unsigned char *eeprom_data); int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len); -- GitLab From 8b6490e5faafb3a16ea45654fb55f9ff086f1495 Mon Sep 17 00:00:00 2001 From: Dipankar Sarma <dipankar@in.ibm.com> Date: Fri, 9 Sep 2005 13:04:07 -0700 Subject: [PATCH 200/563] [PATCH] files: fix rcu initializers First of a number of files_lock scaability patches. Here are the x86 numbers - tiobench on a 4(8)-way (HT) P4 system on ramdisk : (lockfree) Test 2.6.10-vanilla Stdev 2.6.10-fd Stdev ------------------------------------------------------------- Seqread 1400.8 11.52 1465.4 34.27 Randread 1594 8.86 2397.2 29.21 Seqwrite 242.72 3.47 238.46 6.53 Randwrite 445.74 9.15 446.4 9.75 The performance improvement is very significant. We are getting killed by the cacheline bouncing of the files_struct lock here. Writes on ramdisk (ext2) seems to vary just too much to get any meaningful number. Also, With Tridge's thread_perf test on a 4(8)-way (HT) P4 xeon system : 2.6.12-rc5-vanilla : Running test 'readwrite' with 8 tasks Threads 0.34 +/- 0.01 seconds Processes 0.16 +/- 0.00 seconds 2.6.12-rc5-fd : Running test 'readwrite' with 8 tasks Threads 0.17 +/- 0.02 seconds Processes 0.17 +/- 0.02 seconds I repeated the measurements on ramfs (as opposed to ext2 on ramdisk in the earlier measurement) and I got more consistent results from tiobench : 4(8) way xeon P4 ----------------- (lock-free) Test 2.6.12-rc5 Stdev 2.6.12-rc5-fd Stdev ------------------------------------------------------------- Seqread 1282 18.59 1343.6 26.37 Randread 1517 7 2415 34.27 Seqwrite 702.2 5.27 709.46 5.9 Randwrite 846.86 15.15 919.68 21.4 4-way ppc64 ------------ (lock-free) Test 2.6.12-rc5 Stdev 2.6.12-rc5-fd Stdev ------------------------------------------------------------- Seqread 1549 91.16 1569.6 47.2 Randread 1473.6 25.11 1585.4 69.99 Seqwrite 1096.8 20.03 1136 29.61 Randwrite 1189.6 4.04 1275.2 32.96 Also running Tridge's thread_perf test on ppc64 : 2.6.12-rc5-vanilla -------------------- Running test 'readwrite' with 4 tasks Threads 0.20 +/- 0.02 seconds Processes 0.16 +/- 0.01 seconds 2.6.12-rc5-fd -------------------- Running test 'readwrite' with 4 tasks Threads 0.18 +/- 0.04 seconds Processes 0.16 +/- 0.01 seconds The benefits are huge (upto ~60%) in some cases on x86 primarily due to the atomic operations during acquisition of ->file_lock and cache line bouncing in fast path. ppc64 benefits are modest due to LL/SC based locking, but still statistically significant. This patch: RCU head initilizer no longer needs the head varible name since we don't use list.h lists anymore. Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/rcupdate.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index fd276adf0fd5b..4e65eb44adfd0 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -52,8 +52,8 @@ struct rcu_head { void (*func)(struct rcu_head *head); }; -#define RCU_HEAD_INIT(head) { .next = NULL, .func = NULL } -#define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT(head) +#define RCU_HEAD_INIT { .next = NULL, .func = NULL } +#define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT #define INIT_RCU_HEAD(ptr) do { \ (ptr)->next = NULL; (ptr)->func = NULL; \ } while (0) -- GitLab From c0dfb2905126e9e94edebbce8d3e05001301f52d Mon Sep 17 00:00:00 2001 From: Dipankar Sarma <dipankar@in.ibm.com> Date: Fri, 9 Sep 2005 13:04:09 -0700 Subject: [PATCH 201/563] [PATCH] files: rcuref APIs Adds a set of primitives to do reference counting for objects that are looked up without locks using RCU. Signed-off-by: Ravikiran Thirumalai <kiran_th@gmail.com> Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/RCU/rcuref.txt | 74 ++++++++++++ include/linux/rcuref.h | 220 +++++++++++++++++++++++++++++++++++ kernel/rcupdate.c | 14 +++ 3 files changed, 308 insertions(+) create mode 100644 Documentation/RCU/rcuref.txt create mode 100644 include/linux/rcuref.h diff --git a/Documentation/RCU/rcuref.txt b/Documentation/RCU/rcuref.txt new file mode 100644 index 0000000000000..a23fee66064df --- /dev/null +++ b/Documentation/RCU/rcuref.txt @@ -0,0 +1,74 @@ +Refcounter framework for elements of lists/arrays protected by +RCU. + +Refcounting on elements of lists which are protected by traditional +reader/writer spinlocks or semaphores are straight forward as in: + +1. 2. +add() search_and_reference() +{ { + alloc_object read_lock(&list_lock); + ... search_for_element + atomic_set(&el->rc, 1); atomic_inc(&el->rc); + write_lock(&list_lock); ... + add_element read_unlock(&list_lock); + ... ... + write_unlock(&list_lock); } +} + +3. 4. +release_referenced() delete() +{ { + ... write_lock(&list_lock); + atomic_dec(&el->rc, relfunc) ... + ... delete_element +} write_unlock(&list_lock); + ... + if (atomic_dec_and_test(&el->rc)) + kfree(el); + ... + } + +If this list/array is made lock free using rcu as in changing the +write_lock in add() and delete() to spin_lock and changing read_lock +in search_and_reference to rcu_read_lock(), the rcuref_get in +search_and_reference could potentially hold reference to an element which +has already been deleted from the list/array. rcuref_lf_get_rcu takes +care of this scenario. search_and_reference should look as; + +1. 2. +add() search_and_reference() +{ { + alloc_object rcu_read_lock(); + ... search_for_element + atomic_set(&el->rc, 1); if (rcuref_inc_lf(&el->rc)) { + write_lock(&list_lock); rcu_read_unlock(); + return FAIL; + add_element } + ... ... + write_unlock(&list_lock); rcu_read_unlock(); +} } +3. 4. +release_referenced() delete() +{ { + ... write_lock(&list_lock); + rcuref_dec(&el->rc, relfunc) ... + ... delete_element +} write_unlock(&list_lock); + ... + if (rcuref_dec_and_test(&el->rc)) + call_rcu(&el->head, el_free); + ... + } + +Sometimes, reference to the element need to be obtained in the +update (write) stream. In such cases, rcuref_inc_lf might be an overkill +since the spinlock serialising list updates are held. rcuref_inc +is to be used in such cases. +For arches which do not have cmpxchg rcuref_inc_lf +api uses a hashed spinlock implementation and the same hashed spinlock +is acquired in all rcuref_xxx primitives to preserve atomicity. +Note: Use rcuref_inc api only if you need to use rcuref_inc_lf on the +refcounter atleast at one place. Mixing rcuref_inc and atomic_xxx api +might lead to races. rcuref_inc_lf() must be used in lockfree +RCU critical sections only. diff --git a/include/linux/rcuref.h b/include/linux/rcuref.h new file mode 100644 index 0000000000000..e1adbba14b672 --- /dev/null +++ b/include/linux/rcuref.h @@ -0,0 +1,220 @@ +/* + * rcuref.h + * + * Reference counting for elements of lists/arrays protected by + * RCU. + * + * 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. + * + * Copyright (C) IBM Corporation, 2005 + * + * Author: Dipankar Sarma <dipankar@in.ibm.com> + * Ravikiran Thirumalai <kiran_th@gmail.com> + * + * See Documentation/RCU/rcuref.txt for detailed user guide. + * + */ + +#ifndef _RCUREF_H_ +#define _RCUREF_H_ + +#ifdef __KERNEL__ + +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <asm/atomic.h> + +/* + * These APIs work on traditional atomic_t counters used in the + * kernel for reference counting. Under special circumstances + * where a lock-free get() operation races with a put() operation + * these APIs can be used. See Documentation/RCU/rcuref.txt. + */ + +#ifdef __HAVE_ARCH_CMPXCHG + +/** + * rcuref_inc - increment refcount for object. + * @rcuref: reference counter in the object in question. + * + * This should be used only for objects where we use RCU and + * use the rcuref_inc_lf() api to acquire a reference + * in a lock-free reader-side critical section. + */ +static inline void rcuref_inc(atomic_t *rcuref) +{ + atomic_inc(rcuref); +} + +/** + * rcuref_dec - decrement refcount for object. + * @rcuref: reference counter in the object in question. + * + * This should be used only for objects where we use RCU and + * use the rcuref_inc_lf() api to acquire a reference + * in a lock-free reader-side critical section. + */ +static inline void rcuref_dec(atomic_t *rcuref) +{ + atomic_dec(rcuref); +} + +/** + * rcuref_dec_and_test - decrement refcount for object and test + * @rcuref: reference counter in the object. + * @release: pointer to the function that will clean up the object + * when the last reference to the object is released. + * This pointer is required. + * + * Decrement the refcount, and if 0, return 1. Else return 0. + * + * This should be used only for objects where we use RCU and + * use the rcuref_inc_lf() api to acquire a reference + * in a lock-free reader-side critical section. + */ +static inline int rcuref_dec_and_test(atomic_t *rcuref) +{ + return atomic_dec_and_test(rcuref); +} + +/* + * cmpxchg is needed on UP too, if deletions to the list/array can happen + * in interrupt context. + */ + +/** + * rcuref_inc_lf - Take reference to an object in a read-side + * critical section protected by RCU. + * @rcuref: reference counter in the object in question. + * + * Try and increment the refcount by 1. The increment might fail if + * the reference counter has been through a 1 to 0 transition and + * is no longer part of the lock-free list. + * Returns non-zero on successful increment and zero otherwise. + */ +static inline int rcuref_inc_lf(atomic_t *rcuref) +{ + int c, old; + c = atomic_read(rcuref); + while (c && (old = cmpxchg(&rcuref->counter, c, c + 1)) != c) + c = old; + return c; +} + +#else /* !__HAVE_ARCH_CMPXCHG */ + +extern spinlock_t __rcuref_hash[]; + +/* + * Use a hash table of locks to protect the reference count + * since cmpxchg is not available in this arch. + */ +#ifdef CONFIG_SMP +#define RCUREF_HASH_SIZE 4 +#define RCUREF_HASH(k) \ + (&__rcuref_hash[(((unsigned long)k)>>8) & (RCUREF_HASH_SIZE-1)]) +#else +#define RCUREF_HASH_SIZE 1 +#define RCUREF_HASH(k) &__rcuref_hash[0] +#endif /* CONFIG_SMP */ + +/** + * rcuref_inc - increment refcount for object. + * @rcuref: reference counter in the object in question. + * + * This should be used only for objects where we use RCU and + * use the rcuref_inc_lf() api to acquire a reference in a lock-free + * reader-side critical section. + */ +static inline void rcuref_inc(atomic_t *rcuref) +{ + unsigned long flags; + spin_lock_irqsave(RCUREF_HASH(rcuref), flags); + rcuref->counter += 1; + spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags); +} + +/** + * rcuref_dec - decrement refcount for object. + * @rcuref: reference counter in the object in question. + * + * This should be used only for objects where we use RCU and + * use the rcuref_inc_lf() api to acquire a reference in a lock-free + * reader-side critical section. + */ +static inline void rcuref_dec(atomic_t *rcuref) +{ + unsigned long flags; + spin_lock_irqsave(RCUREF_HASH(rcuref), flags); + rcuref->counter -= 1; + spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags); +} + +/** + * rcuref_dec_and_test - decrement refcount for object and test + * @rcuref: reference counter in the object. + * @release: pointer to the function that will clean up the object + * when the last reference to the object is released. + * This pointer is required. + * + * Decrement the refcount, and if 0, return 1. Else return 0. + * + * This should be used only for objects where we use RCU and + * use the rcuref_inc_lf() api to acquire a reference in a lock-free + * reader-side critical section. + */ +static inline int rcuref_dec_and_test(atomic_t *rcuref) +{ + unsigned long flags; + spin_lock_irqsave(RCUREF_HASH(rcuref), flags); + rcuref->counter--; + if (!rcuref->counter) { + spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags); + return 1; + } else { + spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags); + return 0; + } +} + +/** + * rcuref_inc_lf - Take reference to an object of a lock-free collection + * by traversing a lock-free list/array. + * @rcuref: reference counter in the object in question. + * + * Try and increment the refcount by 1. The increment might fail if + * the reference counter has been through a 1 to 0 transition and + * object is no longer part of the lock-free list. + * Returns non-zero on successful increment and zero otherwise. + */ +static inline int rcuref_inc_lf(atomic_t *rcuref) +{ + int ret; + unsigned long flags; + spin_lock_irqsave(RCUREF_HASH(rcuref), flags); + if (rcuref->counter) + ret = rcuref->counter++; + else + ret = 0; + spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags); + return ret; +} + + +#endif /* !__HAVE_ARCH_CMPXCHG */ + +#endif /* __KERNEL__ */ +#endif /* _RCUREF_H_ */ diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index f436993bd590a..bef3b6901b769 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -45,6 +45,7 @@ #include <linux/percpu.h> #include <linux/notifier.h> #include <linux/rcupdate.h> +#include <linux/rcuref.h> #include <linux/cpu.h> /* Definition for rcupdate control block. */ @@ -72,6 +73,19 @@ DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L }; static DEFINE_PER_CPU(struct tasklet_struct, rcu_tasklet) = {NULL}; static int maxbatch = 10; +#ifndef __HAVE_ARCH_CMPXCHG +/* + * We use an array of spinlocks for the rcurefs -- similar to ones in sparc + * 32 bit atomic_t implementations, and a hash function similar to that + * for our refcounting needs. + * Can't help multiprocessors which donot have cmpxchg :( + */ + +spinlock_t __rcuref_hash[RCUREF_HASH_SIZE] = { + [0 ... (RCUREF_HASH_SIZE-1)] = SPIN_LOCK_UNLOCKED +}; +#endif + /** * call_rcu - Queue an RCU callback for invocation after a grace period. * @head: structure to be used for queueing the RCU updates. -- GitLab From badf16621c1f9d1ac753be056fce11b43d6e0be5 Mon Sep 17 00:00:00 2001 From: Dipankar Sarma <dipankar@in.ibm.com> Date: Fri, 9 Sep 2005 13:04:10 -0700 Subject: [PATCH 202/563] [PATCH] files: break up files struct In order for the RCU to work, the file table array, sets and their sizes must be updated atomically. Instead of ensuring this through too many memory barriers, we put the arrays and their sizes in a separate structure. This patch takes the first step of putting the file table elements in a separate structure fdtable that is embedded withing files_struct. It also changes all the users to refer to the file table using files_fdtable() macro. Subsequent applciation of RCU becomes easier after this. Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com> Signed-Off-By: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/alpha/kernel/osf_sys.c | 4 +- arch/ia64/kernel/perfmon.c | 7 ++- arch/sparc64/solaris/ioctl.c | 8 ++-- drivers/char/tty_io.c | 4 +- fs/exec.c | 8 ++-- fs/fcntl.c | 47 +++++++++++++-------- fs/file.c | 42 ++++++++++-------- fs/locks.c | 8 ++-- fs/open.c | 41 ++++++++++-------- fs/proc/array.c | 5 ++- fs/proc/base.c | 4 +- fs/select.c | 12 ++++-- include/linux/file.h | 23 ++++++---- include/linux/init_task.h | 13 ++++-- kernel/exit.c | 21 +++++---- kernel/fork.c | 82 ++++++++++++++++++++++-------------- security/selinux/hooks.c | 6 ++- 17 files changed, 211 insertions(+), 124 deletions(-) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 167fd89f8707a..2b034182a0ca8 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -974,6 +974,7 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, size_t size; long timeout; int ret = -EINVAL; + struct fdtable *fdt; timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { @@ -995,7 +996,8 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, } } - if (n < 0 || n > current->files->max_fdset) + fdt = files_fdtable(current->files); + if (n < 0 || n > fdt->max_fdset) goto out_nofds; /* diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index f1201ac8a1161..4ad97b3b39dcc 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -38,6 +38,7 @@ #include <linux/pagemap.h> #include <linux/mount.h> #include <linux/bitops.h> +#include <linux/rcupdate.h> #include <asm/errno.h> #include <asm/intrinsics.h> @@ -2217,15 +2218,17 @@ static void pfm_free_fd(int fd, struct file *file) { struct files_struct *files = current->files; + struct fdtable *fdt = files_fdtable(files); /* * there ie no fd_uninstall(), so we do it here */ spin_lock(&files->file_lock); - files->fd[fd] = NULL; + rcu_assign_pointer(fdt->fd[fd], NULL); spin_unlock(&files->file_lock); - if (file) put_filp(file); + if (file) + put_filp(file); put_unused_fd(fd); } diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c index cac0a1cf0050b..374766455f5e2 100644 --- a/arch/sparc64/solaris/ioctl.c +++ b/arch/sparc64/solaris/ioctl.c @@ -293,11 +293,13 @@ static struct module_info { static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg) { struct inode *ino; + struct fdtable *fdt; /* I wonder which of these tests are superfluous... --patrik */ spin_lock(¤t->files->file_lock); - if (! current->files->fd[fd] || - ! current->files->fd[fd]->f_dentry || - ! (ino = current->files->fd[fd]->f_dentry->d_inode) || + fdt = files_fdtable(current->files); + if (! fdt->fd[fd] || + ! fdt->fd[fd]->f_dentry || + ! (ino = fdt->fd[fd]->f_dentry->d_inode) || ! S_ISSOCK(ino->i_mode)) { spin_unlock(¤t->files->file_lock); return TBADF; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 6a56ae4f77257..0bfc7af689172 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2454,6 +2454,7 @@ static void __do_SAK(void *arg) int i; struct file *filp; struct tty_ldisc *disc; + struct fdtable *fdt; if (!tty) return; @@ -2480,7 +2481,8 @@ static void __do_SAK(void *arg) task_lock(p); if (p->files) { spin_lock(&p->files->file_lock); - for (i=0; i < p->files->max_fds; i++) { + fdt = files_fdtable(p->files); + for (i=0; i < fdt->max_fds; i++) { filp = fcheck_files(p->files, i); if (!filp) continue; diff --git a/fs/exec.c b/fs/exec.c index 222ab1c572d88..14dd03907ccb5 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -798,6 +798,7 @@ static inline int de_thread(struct task_struct *tsk) static inline void flush_old_files(struct files_struct * files) { long j = -1; + struct fdtable *fdt; spin_lock(&files->file_lock); for (;;) { @@ -805,12 +806,13 @@ static inline void flush_old_files(struct files_struct * files) j++; i = j * __NFDBITS; - if (i >= files->max_fds || i >= files->max_fdset) + fdt = files_fdtable(files); + if (i >= fdt->max_fds || i >= fdt->max_fdset) break; - set = files->close_on_exec->fds_bits[j]; + set = fdt->close_on_exec->fds_bits[j]; if (!set) continue; - files->close_on_exec->fds_bits[j] = 0; + fdt->close_on_exec->fds_bits[j] = 0; spin_unlock(&files->file_lock); for ( ; set ; i++,set >>= 1) { if (set & 1) { diff --git a/fs/fcntl.c b/fs/fcntl.c index 6fbc9d8fcc362..bfecc62380835 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -24,20 +24,24 @@ void fastcall set_close_on_exec(unsigned int fd, int flag) { struct files_struct *files = current->files; + struct fdtable *fdt; spin_lock(&files->file_lock); + fdt = files_fdtable(files); if (flag) - FD_SET(fd, files->close_on_exec); + FD_SET(fd, fdt->close_on_exec); else - FD_CLR(fd, files->close_on_exec); + FD_CLR(fd, fdt->close_on_exec); spin_unlock(&files->file_lock); } static inline int get_close_on_exec(unsigned int fd) { struct files_struct *files = current->files; + struct fdtable *fdt; int res; spin_lock(&files->file_lock); - res = FD_ISSET(fd, files->close_on_exec); + fdt = files_fdtable(files); + res = FD_ISSET(fd, fdt->close_on_exec); spin_unlock(&files->file_lock); return res; } @@ -54,24 +58,26 @@ static int locate_fd(struct files_struct *files, unsigned int newfd; unsigned int start; int error; + struct fdtable *fdt; error = -EINVAL; if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) goto out; + fdt = files_fdtable(files); repeat: /* * Someone might have closed fd's in the range - * orig_start..files->next_fd + * orig_start..fdt->next_fd */ start = orig_start; - if (start < files->next_fd) - start = files->next_fd; + if (start < fdt->next_fd) + start = fdt->next_fd; newfd = start; - if (start < files->max_fdset) { - newfd = find_next_zero_bit(files->open_fds->fds_bits, - files->max_fdset, start); + if (start < fdt->max_fdset) { + newfd = find_next_zero_bit(fdt->open_fds->fds_bits, + fdt->max_fdset, start); } error = -EMFILE; @@ -89,8 +95,8 @@ static int locate_fd(struct files_struct *files, if (error) goto repeat; - if (start <= files->next_fd) - files->next_fd = newfd + 1; + if (start <= fdt->next_fd) + fdt->next_fd = newfd + 1; error = newfd; @@ -101,13 +107,16 @@ static int locate_fd(struct files_struct *files, static int dupfd(struct file *file, unsigned int start) { struct files_struct * files = current->files; + struct fdtable *fdt; int fd; spin_lock(&files->file_lock); fd = locate_fd(files, file, start); if (fd >= 0) { - FD_SET(fd, files->open_fds); - FD_CLR(fd, files->close_on_exec); + /* locate_fd() may have expanded fdtable, load the ptr */ + fdt = files_fdtable(files); + FD_SET(fd, fdt->open_fds); + FD_CLR(fd, fdt->close_on_exec); spin_unlock(&files->file_lock); fd_install(fd, file); } else { @@ -123,6 +132,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) int err = -EBADF; struct file * file, *tofree; struct files_struct * files = current->files; + struct fdtable *fdt; spin_lock(&files->file_lock); if (!(file = fcheck(oldfd))) @@ -148,13 +158,14 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) /* Yes. It's a race. In user space. Nothing sane to do */ err = -EBUSY; - tofree = files->fd[newfd]; - if (!tofree && FD_ISSET(newfd, files->open_fds)) + fdt = files_fdtable(files); + tofree = fdt->fd[newfd]; + if (!tofree && FD_ISSET(newfd, fdt->open_fds)) goto out_fput; - files->fd[newfd] = file; - FD_SET(newfd, files->open_fds); - FD_CLR(newfd, files->close_on_exec); + fdt->fd[newfd] = file; + FD_SET(newfd, fdt->open_fds); + FD_CLR(newfd, fdt->close_on_exec); spin_unlock(&files->file_lock); if (tofree) diff --git a/fs/file.c b/fs/file.c index 92b5f25985d2f..f5926ce73f373 100644 --- a/fs/file.c +++ b/fs/file.c @@ -59,13 +59,15 @@ static int expand_fd_array(struct files_struct *files, int nr) { struct file **new_fds; int error, nfds; + struct fdtable *fdt; error = -EMFILE; - if (files->max_fds >= NR_OPEN || nr >= NR_OPEN) + fdt = files_fdtable(files); + if (fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) goto out; - nfds = files->max_fds; + nfds = fdt->max_fds; spin_unlock(&files->file_lock); /* @@ -95,13 +97,14 @@ static int expand_fd_array(struct files_struct *files, int nr) goto out; /* Copy the existing array and install the new pointer */ + fdt = files_fdtable(files); - if (nfds > files->max_fds) { + if (nfds > fdt->max_fds) { struct file **old_fds; int i; - old_fds = xchg(&files->fd, new_fds); - i = xchg(&files->max_fds, nfds); + old_fds = xchg(&fdt->fd, new_fds); + i = xchg(&fdt->max_fds, nfds); /* Don't copy/clear the array if we are creating a new fd array for fork() */ @@ -164,12 +167,14 @@ static int expand_fdset(struct files_struct *files, int nr) { fd_set *new_openset = NULL, *new_execset = NULL; int error, nfds = 0; + struct fdtable *fdt; error = -EMFILE; - if (files->max_fdset >= NR_OPEN || nr >= NR_OPEN) + fdt = files_fdtable(files); + if (fdt->max_fdset >= NR_OPEN || nr >= NR_OPEN) goto out; - nfds = files->max_fdset; + nfds = fdt->max_fdset; spin_unlock(&files->file_lock); /* Expand to the max in easy steps */ @@ -193,24 +198,25 @@ static int expand_fdset(struct files_struct *files, int nr) error = 0; /* Copy the existing tables and install the new pointers */ - if (nfds > files->max_fdset) { - int i = files->max_fdset / (sizeof(unsigned long) * 8); - int count = (nfds - files->max_fdset) / 8; + fdt = files_fdtable(files); + if (nfds > fdt->max_fdset) { + int i = fdt->max_fdset / (sizeof(unsigned long) * 8); + int count = (nfds - fdt->max_fdset) / 8; /* * Don't copy the entire array if the current fdset is * not yet initialised. */ if (i) { - memcpy (new_openset, files->open_fds, files->max_fdset/8); - memcpy (new_execset, files->close_on_exec, files->max_fdset/8); + memcpy (new_openset, fdt->open_fds, fdt->max_fdset/8); + memcpy (new_execset, fdt->close_on_exec, fdt->max_fdset/8); memset (&new_openset->fds_bits[i], 0, count); memset (&new_execset->fds_bits[i], 0, count); } - nfds = xchg(&files->max_fdset, nfds); - new_openset = xchg(&files->open_fds, new_openset); - new_execset = xchg(&files->close_on_exec, new_execset); + nfds = xchg(&fdt->max_fdset, nfds); + new_openset = xchg(&fdt->open_fds, new_openset); + new_execset = xchg(&fdt->close_on_exec, new_execset); spin_unlock(&files->file_lock); free_fdset (new_openset, nfds); free_fdset (new_execset, nfds); @@ -237,13 +243,15 @@ static int expand_fdset(struct files_struct *files, int nr) int expand_files(struct files_struct *files, int nr) { int err, expand = 0; + struct fdtable *fdt; - if (nr >= files->max_fdset) { + fdt = files_fdtable(files); + if (nr >= fdt->max_fdset) { expand = 1; if ((err = expand_fdset(files, nr))) goto out; } - if (nr >= files->max_fds) { + if (nr >= fdt->max_fds) { expand = 1; if ((err = expand_fd_array(files, nr))) goto out; diff --git a/fs/locks.c b/fs/locks.c index 11956b6179ff8..c2c09b4798d60 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2198,21 +2198,23 @@ void steal_locks(fl_owner_t from) { struct files_struct *files = current->files; int i, j; + struct fdtable *fdt; if (from == files) return; lock_kernel(); j = 0; + fdt = files_fdtable(files); for (;;) { unsigned long set; i = j * __NFDBITS; - if (i >= files->max_fdset || i >= files->max_fds) + if (i >= fdt->max_fdset || i >= fdt->max_fds) break; - set = files->open_fds->fds_bits[j++]; + set = fdt->open_fds->fds_bits[j++]; while (set) { if (set & 1) { - struct file *file = files->fd[i]; + struct file *file = fdt->fd[i]; if (file) __steal_locks(file, from); } diff --git a/fs/open.c b/fs/open.c index 4ee2dcc31c285..b6542516a0cab 100644 --- a/fs/open.c +++ b/fs/open.c @@ -842,14 +842,16 @@ int get_unused_fd(void) { struct files_struct * files = current->files; int fd, error; + struct fdtable *fdt; error = -EMFILE; spin_lock(&files->file_lock); repeat: - fd = find_next_zero_bit(files->open_fds->fds_bits, - files->max_fdset, - files->next_fd); + fdt = files_fdtable(files); + fd = find_next_zero_bit(fdt->open_fds->fds_bits, + fdt->max_fdset, + fdt->next_fd); /* * N.B. For clone tasks sharing a files structure, this test @@ -872,14 +874,14 @@ int get_unused_fd(void) goto repeat; } - FD_SET(fd, files->open_fds); - FD_CLR(fd, files->close_on_exec); - files->next_fd = fd + 1; + FD_SET(fd, fdt->open_fds); + FD_CLR(fd, fdt->close_on_exec); + fdt->next_fd = fd + 1; #if 1 /* Sanity check */ - if (files->fd[fd] != NULL) { + if (fdt->fd[fd] != NULL) { printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); - files->fd[fd] = NULL; + fdt->fd[fd] = NULL; } #endif error = fd; @@ -893,9 +895,10 @@ EXPORT_SYMBOL(get_unused_fd); static inline void __put_unused_fd(struct files_struct *files, unsigned int fd) { - __FD_CLR(fd, files->open_fds); - if (fd < files->next_fd) - files->next_fd = fd; + struct fdtable *fdt = files_fdtable(files); + __FD_CLR(fd, fdt->open_fds); + if (fd < fdt->next_fd) + fdt->next_fd = fd; } void fastcall put_unused_fd(unsigned int fd) @@ -924,10 +927,12 @@ EXPORT_SYMBOL(put_unused_fd); void fastcall fd_install(unsigned int fd, struct file * file) { struct files_struct *files = current->files; + struct fdtable *fdt; spin_lock(&files->file_lock); - if (unlikely(files->fd[fd] != NULL)) + fdt = files_fdtable(files); + if (unlikely(fdt->fd[fd] != NULL)) BUG(); - files->fd[fd] = file; + fdt->fd[fd] = file; spin_unlock(&files->file_lock); } @@ -1010,15 +1015,17 @@ asmlinkage long sys_close(unsigned int fd) { struct file * filp; struct files_struct *files = current->files; + struct fdtable *fdt; spin_lock(&files->file_lock); - if (fd >= files->max_fds) + fdt = files_fdtable(files); + if (fd >= fdt->max_fds) goto out_unlock; - filp = files->fd[fd]; + filp = fdt->fd[fd]; if (!filp) goto out_unlock; - files->fd[fd] = NULL; - FD_CLR(fd, files->close_on_exec); + fdt->fd[fd] = NULL; + FD_CLR(fd, fdt->close_on_exec); __put_unused_fd(files, fd); spin_unlock(&files->file_lock); return filp_close(filp, files); diff --git a/fs/proc/array.c b/fs/proc/array.c index 37668fe998ad0..d88d518d30f60 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -159,6 +159,7 @@ static inline char * task_state(struct task_struct *p, char *buffer) { struct group_info *group_info; int g; + struct fdtable *fdt = NULL; read_lock(&tasklist_lock); buffer += sprintf(buffer, @@ -179,10 +180,12 @@ static inline char * task_state(struct task_struct *p, char *buffer) p->gid, p->egid, p->sgid, p->fsgid); read_unlock(&tasklist_lock); task_lock(p); + if (p->files) + fdt = files_fdtable(p->files); buffer += sprintf(buffer, "FDSize:\t%d\n" "Groups:\t", - p->files ? p->files->max_fds : 0); + fdt ? fdt->max_fds : 0); group_info = p->group_info; get_group_info(group_info); diff --git a/fs/proc/base.c b/fs/proc/base.c index 84751f3f52d53..d0087a0b024be 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1039,6 +1039,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) int retval; char buf[NUMBUF]; struct files_struct * files; + struct fdtable *fdt; retval = -ENOENT; if (!pid_alive(p)) @@ -1062,8 +1063,9 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) if (!files) goto out; spin_lock(&files->file_lock); + fdt = files_fdtable(files); for (fd = filp->f_pos-2; - fd < files->max_fds; + fd < fdt->max_fds; fd++, filp->f_pos++) { unsigned int i,j; diff --git a/fs/select.c b/fs/select.c index b80e7eb0ac0da..2e56325c73c47 100644 --- a/fs/select.c +++ b/fs/select.c @@ -132,11 +132,13 @@ static int max_select_fd(unsigned long n, fd_set_bits *fds) unsigned long *open_fds; unsigned long set; int max; + struct fdtable *fdt; /* handle last in-complete long-word first */ set = ~(~0UL << (n & (__NFDBITS-1))); n /= __NFDBITS; - open_fds = current->files->open_fds->fds_bits+n; + fdt = files_fdtable(current->files); + open_fds = fdt->open_fds->fds_bits+n; max = 0; if (set) { set &= BITS(fds, n); @@ -299,6 +301,7 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s char *bits; long timeout; int ret, size, max_fdset; + struct fdtable *fdt; timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { @@ -326,7 +329,8 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s goto out_nofds; /* max_fdset can increase, so grab it once to avoid race */ - max_fdset = current->files->max_fdset; + fdt = files_fdtable(current->files); + max_fdset = fdt->max_fdset; if (n > max_fdset) n = max_fdset; @@ -464,9 +468,11 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti unsigned int i; struct poll_list *head; struct poll_list *walk; + struct fdtable *fdt; /* Do a sanity check on nfds ... */ - if (nfds > current->files->max_fdset && nfds > OPEN_MAX) + fdt = files_fdtable(current->files); + if (nfds > fdt->max_fdset && nfds > OPEN_MAX) return -EINVAL; if (timeout) { diff --git a/include/linux/file.h b/include/linux/file.h index 5206beb9a80e5..db372230848ed 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -16,23 +16,29 @@ */ #define NR_OPEN_DEFAULT BITS_PER_LONG +struct fdtable { + unsigned int max_fds; + int max_fdset; + int next_fd; + struct file ** fd; /* current fd array */ + fd_set *close_on_exec; + fd_set *open_fds; +}; + /* * Open file table structure */ struct files_struct { atomic_t count; spinlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */ - int max_fds; - int max_fdset; - int next_fd; - struct file ** fd; /* current fd array */ - fd_set *close_on_exec; - fd_set *open_fds; + struct fdtable fdtab; fd_set close_on_exec_init; fd_set open_fds_init; struct file * fd_array[NR_OPEN_DEFAULT]; }; +#define files_fdtable(files) (&(files)->fdtab) + extern void FASTCALL(__fput(struct file *)); extern void FASTCALL(fput(struct file *)); @@ -63,9 +69,10 @@ extern int expand_files(struct files_struct *, int nr); static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) { struct file * file = NULL; + struct fdtable *fdt = files_fdtable(files); - if (fd < files->max_fds) - file = files->fd[fd]; + if (fd < fdt->max_fds) + file = fdt->fd[fd]; return file; } diff --git a/include/linux/init_task.h b/include/linux/init_task.h index c727c195a91a8..94aefa54a1b5f 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -3,16 +3,21 @@ #include <linux/file.h> -#define INIT_FILES \ -{ \ - .count = ATOMIC_INIT(1), \ - .file_lock = SPIN_LOCK_UNLOCKED, \ +#define INIT_FDTABLE \ +{ \ .max_fds = NR_OPEN_DEFAULT, \ .max_fdset = __FD_SETSIZE, \ .next_fd = 0, \ .fd = &init_files.fd_array[0], \ .close_on_exec = &init_files.close_on_exec_init, \ .open_fds = &init_files.open_fds_init, \ +} + +#define INIT_FILES \ +{ \ + .count = ATOMIC_INIT(1), \ + .file_lock = SPIN_LOCK_UNLOCKED, \ + .fdtab = INIT_FDTABLE, \ .close_on_exec_init = { { 0, } }, \ .open_fds_init = { { 0, } }, \ .fd_array = { NULL, } \ diff --git a/kernel/exit.c b/kernel/exit.c index 5b0fb9f09f212..83beb1e93b18c 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -368,17 +368,19 @@ EXPORT_SYMBOL(daemonize); static inline void close_files(struct files_struct * files) { int i, j; + struct fdtable *fdt; j = 0; + fdt = files_fdtable(files); for (;;) { unsigned long set; i = j * __NFDBITS; - if (i >= files->max_fdset || i >= files->max_fds) + if (i >= fdt->max_fdset || i >= fdt->max_fds) break; - set = files->open_fds->fds_bits[j++]; + set = fdt->open_fds->fds_bits[j++]; while (set) { if (set & 1) { - struct file * file = xchg(&files->fd[i], NULL); + struct file * file = xchg(&fdt->fd[i], NULL); if (file) filp_close(file, files); } @@ -403,16 +405,19 @@ struct files_struct *get_files_struct(struct task_struct *task) void fastcall put_files_struct(struct files_struct *files) { + struct fdtable *fdt; + if (atomic_dec_and_test(&files->count)) { close_files(files); /* * Free the fd and fdset arrays if we expanded them. */ - if (files->fd != &files->fd_array[0]) - free_fd_array(files->fd, files->max_fds); - if (files->max_fdset > __FD_SETSIZE) { - free_fdset(files->open_fds, files->max_fdset); - free_fdset(files->close_on_exec, files->max_fdset); + fdt = files_fdtable(files); + if (fdt->fd != &files->fd_array[0]) + free_fd_array(fdt->fd, fdt->max_fds); + if (fdt->max_fdset > __FD_SETSIZE) { + free_fdset(fdt->open_fds, fdt->max_fdset); + free_fdset(fdt->close_on_exec, fdt->max_fdset); } kmem_cache_free(files_cachep, files); } diff --git a/kernel/fork.c b/kernel/fork.c index b25802065031e..ecc694debb50c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -568,21 +568,47 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk) static int count_open_files(struct files_struct *files, int size) { int i; + struct fdtable *fdt; /* Find the last open fd */ + fdt = files_fdtable(files); for (i = size/(8*sizeof(long)); i > 0; ) { - if (files->open_fds->fds_bits[--i]) + if (fdt->open_fds->fds_bits[--i]) break; } i = (i+1) * 8 * sizeof(long); return i; } +static struct files_struct *alloc_files(void) +{ + struct files_struct *newf; + struct fdtable *fdt; + + newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); + if (!newf) + goto out; + + atomic_set(&newf->count, 1); + + spin_lock_init(&newf->file_lock); + fdt = files_fdtable(newf); + fdt->next_fd = 0; + fdt->max_fds = NR_OPEN_DEFAULT; + fdt->max_fdset = __FD_SETSIZE; + fdt->close_on_exec = &newf->close_on_exec_init; + fdt->open_fds = &newf->open_fds_init; + fdt->fd = &newf->fd_array[0]; +out: + return newf; +} + static int copy_files(unsigned long clone_flags, struct task_struct * tsk) { struct files_struct *oldf, *newf; struct file **old_fds, **new_fds; int open_files, size, i, error = 0, expand; + struct fdtable *old_fdt, *new_fdt; /* * A background process may not have any files ... @@ -603,35 +629,27 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) */ tsk->files = NULL; error = -ENOMEM; - newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); - if (!newf) + newf = alloc_files(); + if (!newf) goto out; - atomic_set(&newf->count, 1); - - spin_lock_init(&newf->file_lock); - newf->next_fd = 0; - newf->max_fds = NR_OPEN_DEFAULT; - newf->max_fdset = __FD_SETSIZE; - newf->close_on_exec = &newf->close_on_exec_init; - newf->open_fds = &newf->open_fds_init; - newf->fd = &newf->fd_array[0]; - spin_lock(&oldf->file_lock); - - open_files = count_open_files(oldf, oldf->max_fdset); + old_fdt = files_fdtable(oldf); + new_fdt = files_fdtable(newf); + size = old_fdt->max_fdset; + open_files = count_open_files(oldf, old_fdt->max_fdset); expand = 0; /* * Check whether we need to allocate a larger fd array or fd set. * Note: we're not a clone task, so the open count won't change. */ - if (open_files > newf->max_fdset) { - newf->max_fdset = 0; + if (open_files > new_fdt->max_fdset) { + new_fdt->max_fdset = 0; expand = 1; } - if (open_files > newf->max_fds) { - newf->max_fds = 0; + if (open_files > new_fdt->max_fds) { + new_fdt->max_fds = 0; expand = 1; } @@ -646,11 +664,11 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) spin_lock(&oldf->file_lock); } - old_fds = oldf->fd; - new_fds = newf->fd; + old_fds = old_fdt->fd; + new_fds = new_fdt->fd; - memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, open_files/8); - memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, open_files/8); + memcpy(new_fdt->open_fds->fds_bits, old_fdt->open_fds->fds_bits, open_files/8); + memcpy(new_fdt->close_on_exec->fds_bits, old_fdt->close_on_exec->fds_bits, open_files/8); for (i = open_files; i != 0; i--) { struct file *f = *old_fds++; @@ -663,24 +681,24 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) * is partway through open(). So make sure that this * fd is available to the new process. */ - FD_CLR(open_files - i, newf->open_fds); + FD_CLR(open_files - i, new_fdt->open_fds); } *new_fds++ = f; } spin_unlock(&oldf->file_lock); /* compute the remainder to be cleared */ - size = (newf->max_fds - open_files) * sizeof(struct file *); + size = (new_fdt->max_fds - open_files) * sizeof(struct file *); /* This is long word aligned thus could use a optimized version */ memset(new_fds, 0, size); - if (newf->max_fdset > open_files) { - int left = (newf->max_fdset-open_files)/8; + if (new_fdt->max_fdset > open_files) { + int left = (new_fdt->max_fdset-open_files)/8; int start = open_files / (8 * sizeof(unsigned long)); - memset(&newf->open_fds->fds_bits[start], 0, left); - memset(&newf->close_on_exec->fds_bits[start], 0, left); + memset(&new_fdt->open_fds->fds_bits[start], 0, left); + memset(&new_fdt->close_on_exec->fds_bits[start], 0, left); } tsk->files = newf; @@ -689,9 +707,9 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) return error; out_release: - free_fdset (newf->close_on_exec, newf->max_fdset); - free_fdset (newf->open_fds, newf->max_fdset); - free_fd_array(newf->fd, newf->max_fds); + free_fdset (new_fdt->close_on_exec, new_fdt->max_fdset); + free_fdset (new_fdt->open_fds, new_fdt->max_fdset); + free_fd_array(new_fdt->fd, new_fdt->max_fds); kmem_cache_free(files_cachep, newf); goto out; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3f0b533be92c7..acb5a495a902f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1594,6 +1594,7 @@ static inline void flush_unauthorized_files(struct files_struct * files) struct avc_audit_data ad; struct file *file, *devnull = NULL; struct tty_struct *tty = current->signal->tty; + struct fdtable *fdt; long j = -1; if (tty) { @@ -1627,9 +1628,10 @@ static inline void flush_unauthorized_files(struct files_struct * files) j++; i = j * __NFDBITS; - if (i >= files->max_fds || i >= files->max_fdset) + fdt = files_fdtable(files); + if (i >= fdt->max_fds || i >= fdt->max_fdset) break; - set = files->open_fds->fds_bits[j]; + set = fdt->open_fds->fds_bits[j]; if (!set) continue; spin_unlock(&files->file_lock); -- GitLab From 6e72ad2c581de121cc7e772469e2a8f6b1fd4379 Mon Sep 17 00:00:00 2001 From: Dipankar Sarma <dipankar@in.ibm.com> Date: Fri, 9 Sep 2005 13:04:12 -0700 Subject: [PATCH 203/563] [PATCH] files-sparc64-fix 2 Fix sparc64 timod to use the new files_fdtable() api to get the fd table. This is necessary for RCUification. Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/sparc64/solaris/timod.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c index 022c80f433923..aaad29c35c838 100644 --- a/arch/sparc64/solaris/timod.c +++ b/arch/sparc64/solaris/timod.c @@ -143,9 +143,11 @@ static struct T_primsg *timod_mkctl(int size) static void timod_wake_socket(unsigned int fd) { struct socket *sock; + struct fdtable *fdt; SOLD("wakeing socket"); - sock = SOCKET_I(current->files->fd[fd]->f_dentry->d_inode); + fdt = files_fdtable(current->files); + sock = SOCKET_I(fdt->fd[fd]->f_dentry->d_inode); wake_up_interruptible(&sock->wait); read_lock(&sock->sk->sk_callback_lock); if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) @@ -157,9 +159,11 @@ static void timod_wake_socket(unsigned int fd) static void timod_queue(unsigned int fd, struct T_primsg *it) { struct sol_socket_struct *sock; + struct fdtable *fdt; SOLD("queuing primsg"); - sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + fdt = files_fdtable(current->files); + sock = (struct sol_socket_struct *)fdt->fd[fd]->private_data; it->next = sock->pfirst; sock->pfirst = it; if (!sock->plast) @@ -171,9 +175,11 @@ static void timod_queue(unsigned int fd, struct T_primsg *it) static void timod_queue_end(unsigned int fd, struct T_primsg *it) { struct sol_socket_struct *sock; + struct fdtable *fdt; SOLD("queuing primsg at end"); - sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + fdt = files_fdtable(current->files); + sock = (struct sol_socket_struct *)fdt->fd[fd]->private_data; it->next = NULL; if (sock->plast) sock->plast->next = it; @@ -344,6 +350,7 @@ int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len, char *buf; struct file *filp; struct inode *ino; + struct fdtable *fdt; struct sol_socket_struct *sock; mm_segment_t old_fs = get_fs(); long args[6]; @@ -351,7 +358,9 @@ int timod_putmsg(unsigned int fd, char __user *ctl_buf, int ctl_len, (int (*)(int, unsigned long __user *))SYS(socketcall); int (*sys_sendto)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int) = (int (*)(int, void __user *, size_t, unsigned, struct sockaddr __user *, int))SYS(sendto); - filp = current->files->fd[fd]; + + fdt = files_fdtable(current->files); + filp = fdt->fd[fd]; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLD("entry"); @@ -620,6 +629,7 @@ int timod_getmsg(unsigned int fd, char __user *ctl_buf, int ctl_maxlen, s32 __us int oldflags; struct file *filp; struct inode *ino; + struct fdtable *fdt; struct sol_socket_struct *sock; struct T_unitdata_ind udi; mm_segment_t old_fs = get_fs(); @@ -632,7 +642,8 @@ int timod_getmsg(unsigned int fd, char __user *ctl_buf, int ctl_maxlen, s32 __us SOLD("entry"); SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p)); - filp = current->files->fd[fd]; + fdt = files_fdtable(current->files); + filp = fdt->fd[fd]; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL)); @@ -844,12 +855,14 @@ asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3) int __user *flgptr; int flags; int error = -EBADF; + struct fdtable *fdt; SOLD("entry"); lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + fdt = files_fdtable(current->files); + filp = fdt->fd[fd]; if(!filp) goto out; ino = filp->f_dentry->d_inode; @@ -910,12 +923,14 @@ asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3) struct strbuf ctl, dat; int flags = (int) arg3; int error = -EBADF; + struct fdtable *fdt; SOLD("entry"); lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + fdt = files_fdtable(current->files); + filp = fdt->fd[fd]; if(!filp) goto out; ino = filp->f_dentry->d_inode; -- GitLab From ab2af1f5005069321c5d130f09cce577b03f43ef Mon Sep 17 00:00:00 2001 From: Dipankar Sarma <dipankar@in.ibm.com> Date: Fri, 9 Sep 2005 13:04:13 -0700 Subject: [PATCH 204/563] [PATCH] files: files struct with RCU Patch to eliminate struct files_struct.file_lock spinlock on the reader side and use rcu refcounting rcuref_xxx api for the f_count refcounter. The updates to the fdtable are done by allocating a new fdtable structure and setting files->fdt to point to the new structure. The fdtable structure is protected by RCU thereby allowing lock-free lookup. For fd arrays/sets that are vmalloced, we use keventd to free them since RCU callbacks can't sleep. A global list of fdtable to be freed is not scalable, so we use a per-cpu list. If keventd is already handling the current cpu's work, we use a timer to defer queueing of that work. Since the last publication, this patch has been re-written to avoid using explicit memory barriers and use rcu_assign_pointer(), rcu_dereference() premitives instead. This required that the fd information is kept in a separate structure (fdtable) and updated atomically. Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/aio.c | 3 +- fs/fcntl.c | 13 +- fs/file.c | 389 +++++++++++++++++++++++++------------- fs/file_table.c | 40 ++-- fs/open.c | 8 +- include/linux/file.h | 11 +- include/linux/fs.h | 4 +- include/linux/init_task.h | 5 + kernel/exit.c | 15 +- kernel/fork.c | 23 ++- 10 files changed, 345 insertions(+), 166 deletions(-) diff --git a/fs/aio.c b/fs/aio.c index 201c1847fa07b..38f62680fd63d 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -29,6 +29,7 @@ #include <linux/highmem.h> #include <linux/workqueue.h> #include <linux/security.h> +#include <linux/rcuref.h> #include <asm/kmap_types.h> #include <asm/uaccess.h> @@ -499,7 +500,7 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) /* Must be done under the lock to serialise against cancellation. * Call this aio_fput as it duplicates fput via the fput_work. */ - if (unlikely(atomic_dec_and_test(&req->ki_filp->f_count))) { + if (unlikely(rcuref_dec_and_test(&req->ki_filp->f_count))) { get_ioctx(ctx); spin_lock(&fput_lock); list_add(&req->ki_list, &fput_head); diff --git a/fs/fcntl.c b/fs/fcntl.c index bfecc62380835..d2f3ed8acd932 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -16,6 +16,7 @@ #include <linux/security.h> #include <linux/ptrace.h> #include <linux/signal.h> +#include <linux/rcupdate.h> #include <asm/poll.h> #include <asm/siginfo.h> @@ -64,8 +65,8 @@ static int locate_fd(struct files_struct *files, if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) goto out; - fdt = files_fdtable(files); repeat: + fdt = files_fdtable(files); /* * Someone might have closed fd's in the range * orig_start..fdt->next_fd @@ -95,9 +96,15 @@ static int locate_fd(struct files_struct *files, if (error) goto repeat; + /* + * We reacquired files_lock, so we are safe as long as + * we reacquire the fdtable pointer and use it while holding + * the lock, no one can free it during that time. + */ + fdt = files_fdtable(files); if (start <= fdt->next_fd) fdt->next_fd = newfd + 1; - + error = newfd; out: @@ -163,7 +170,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) if (!tofree && FD_ISSET(newfd, fdt->open_fds)) goto out_fput; - fdt->fd[newfd] = file; + rcu_assign_pointer(fdt->fd[newfd], file); FD_SET(newfd, fdt->open_fds); FD_CLR(newfd, fdt->close_on_exec); spin_unlock(&files->file_lock); diff --git a/fs/file.c b/fs/file.c index f5926ce73f373..2127a7b9dc3a6 100644 --- a/fs/file.c +++ b/fs/file.c @@ -13,6 +13,25 @@ #include <linux/vmalloc.h> #include <linux/file.h> #include <linux/bitops.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/rcupdate.h> +#include <linux/workqueue.h> + +struct fdtable_defer { + spinlock_t lock; + struct work_struct wq; + struct timer_list timer; + struct fdtable *next; +}; + +/* + * We use this list to defer free fdtables that have vmalloced + * sets/arrays. By keeping a per-cpu list, we avoid having to embed + * the work_struct in fdtable itself which avoids a 64 byte (i386) increase in + * this per-task structure. + */ +static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list); /* @@ -48,85 +67,143 @@ void free_fd_array(struct file **array, int num) vfree(array); } -/* - * Expand the fd array in the files_struct. Called with the files - * spinlock held for write. - */ - -static int expand_fd_array(struct files_struct *files, int nr) - __releases(files->file_lock) - __acquires(files->file_lock) +static void __free_fdtable(struct fdtable *fdt) { - struct file **new_fds; - int error, nfds; - struct fdtable *fdt; + int fdset_size, fdarray_size; - - error = -EMFILE; - fdt = files_fdtable(files); - if (fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) - goto out; + fdset_size = fdt->max_fdset / 8; + fdarray_size = fdt->max_fds * sizeof(struct file *); + free_fdset(fdt->open_fds, fdset_size); + free_fdset(fdt->close_on_exec, fdset_size); + free_fd_array(fdt->fd, fdarray_size); + kfree(fdt); +} - nfds = fdt->max_fds; - spin_unlock(&files->file_lock); +static void fdtable_timer(unsigned long data) +{ + struct fdtable_defer *fddef = (struct fdtable_defer *)data; - /* - * Expand to the max in easy steps, and keep expanding it until - * we have enough for the requested fd array size. + spin_lock(&fddef->lock); + /* + * If someone already emptied the queue return. */ + if (!fddef->next) + goto out; + if (!schedule_work(&fddef->wq)) + mod_timer(&fddef->timer, 5); +out: + spin_unlock(&fddef->lock); +} - do { -#if NR_OPEN_DEFAULT < 256 - if (nfds < 256) - nfds = 256; - else -#endif - if (nfds < (PAGE_SIZE / sizeof(struct file *))) - nfds = PAGE_SIZE / sizeof(struct file *); - else { - nfds = nfds * 2; - if (nfds > NR_OPEN) - nfds = NR_OPEN; - } - } while (nfds <= nr); +static void free_fdtable_work(struct fdtable_defer *f) +{ + struct fdtable *fdt; - error = -ENOMEM; - new_fds = alloc_fd_array(nfds); - spin_lock(&files->file_lock); - if (!new_fds) - goto out; + spin_lock_bh(&f->lock); + fdt = f->next; + f->next = NULL; + spin_unlock_bh(&f->lock); + while(fdt) { + struct fdtable *next = fdt->next; + __free_fdtable(fdt); + fdt = next; + } +} - /* Copy the existing array and install the new pointer */ - fdt = files_fdtable(files); +static void free_fdtable_rcu(struct rcu_head *rcu) +{ + struct fdtable *fdt = container_of(rcu, struct fdtable, rcu); + int fdset_size, fdarray_size; + struct fdtable_defer *fddef; - if (nfds > fdt->max_fds) { - struct file **old_fds; - int i; - - old_fds = xchg(&fdt->fd, new_fds); - i = xchg(&fdt->max_fds, nfds); - - /* Don't copy/clear the array if we are creating a new - fd array for fork() */ - if (i) { - memcpy(new_fds, old_fds, i * sizeof(struct file *)); - /* clear the remainder of the array */ - memset(&new_fds[i], 0, - (nfds-i) * sizeof(struct file *)); - - spin_unlock(&files->file_lock); - free_fd_array(old_fds, i); - spin_lock(&files->file_lock); - } + BUG_ON(!fdt); + fdset_size = fdt->max_fdset / 8; + fdarray_size = fdt->max_fds * sizeof(struct file *); + + if (fdt->free_files) { + /* + * The this fdtable was embedded in the files structure + * and the files structure itself was getting destroyed. + * It is now safe to free the files structure. + */ + kmem_cache_free(files_cachep, fdt->free_files); + return; + } + if (fdt->max_fdset <= __FD_SETSIZE && fdt->max_fds <= NR_OPEN_DEFAULT) { + /* + * The fdtable was embedded + */ + return; + } + if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) { + kfree(fdt->open_fds); + kfree(fdt->close_on_exec); + kfree(fdt->fd); + kfree(fdt); } else { - /* Somebody expanded the array while we slept ... */ - spin_unlock(&files->file_lock); - free_fd_array(new_fds, nfds); - spin_lock(&files->file_lock); + fddef = &get_cpu_var(fdtable_defer_list); + spin_lock(&fddef->lock); + fdt->next = fddef->next; + fddef->next = fdt; + /* + * vmallocs are handled from the workqueue context. + * If the per-cpu workqueue is running, then we + * defer work scheduling through a timer. + */ + if (!schedule_work(&fddef->wq)) + mod_timer(&fddef->timer, 5); + spin_unlock(&fddef->lock); + put_cpu_var(fdtable_defer_list); } - error = 0; -out: - return error; +} + +void free_fdtable(struct fdtable *fdt) +{ + if (fdt->free_files || fdt->max_fdset > __FD_SETSIZE || + fdt->max_fds > NR_OPEN_DEFAULT) + call_rcu(&fdt->rcu, free_fdtable_rcu); +} + +/* + * Expand the fdset in the files_struct. Called with the files spinlock + * held for write. + */ +static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt) +{ + int i; + int count; + + BUG_ON(nfdt->max_fdset < fdt->max_fdset); + BUG_ON(nfdt->max_fds < fdt->max_fds); + /* Copy the existing tables and install the new pointers */ + + i = fdt->max_fdset / (sizeof(unsigned long) * 8); + count = (nfdt->max_fdset - fdt->max_fdset) / 8; + + /* + * Don't copy the entire array if the current fdset is + * not yet initialised. + */ + if (i) { + memcpy (nfdt->open_fds, fdt->open_fds, + fdt->max_fdset/8); + memcpy (nfdt->close_on_exec, fdt->close_on_exec, + fdt->max_fdset/8); + memset (&nfdt->open_fds->fds_bits[i], 0, count); + memset (&nfdt->close_on_exec->fds_bits[i], 0, count); + } + + /* Don't copy/clear the array if we are creating a new + fd array for fork() */ + if (fdt->max_fds) { + memcpy(nfdt->fd, fdt->fd, + fdt->max_fds * sizeof(struct file *)); + /* clear the remainder of the array */ + memset(&nfdt->fd[fdt->max_fds], 0, + (nfdt->max_fds - fdt->max_fds) * + sizeof(struct file *)); + } + nfdt->next_fd = fdt->next_fd; } /* @@ -157,28 +234,21 @@ void free_fdset(fd_set *array, int num) vfree(array); } -/* - * Expand the fdset in the files_struct. Called with the files spinlock - * held for write. - */ -static int expand_fdset(struct files_struct *files, int nr) - __releases(file->file_lock) - __acquires(file->file_lock) +static struct fdtable *alloc_fdtable(int nr) { - fd_set *new_openset = NULL, *new_execset = NULL; - int error, nfds = 0; - struct fdtable *fdt; - - error = -EMFILE; - fdt = files_fdtable(files); - if (fdt->max_fdset >= NR_OPEN || nr >= NR_OPEN) - goto out; + struct fdtable *fdt = NULL; + int nfds = 0; + fd_set *new_openset = NULL, *new_execset = NULL; + struct file **new_fds; - nfds = fdt->max_fdset; - spin_unlock(&files->file_lock); + fdt = kmalloc(sizeof(*fdt), GFP_KERNEL); + if (!fdt) + goto out; + memset(fdt, 0, sizeof(*fdt)); - /* Expand to the max in easy steps */ - do { + nfds = __FD_SETSIZE; + /* Expand to the max in easy steps */ + do { if (nfds < (PAGE_SIZE * 8)) nfds = PAGE_SIZE * 8; else { @@ -188,50 +258,88 @@ static int expand_fdset(struct files_struct *files, int nr) } } while (nfds <= nr); - error = -ENOMEM; - new_openset = alloc_fdset(nfds); - new_execset = alloc_fdset(nfds); - spin_lock(&files->file_lock); - if (!new_openset || !new_execset) + new_openset = alloc_fdset(nfds); + new_execset = alloc_fdset(nfds); + if (!new_openset || !new_execset) + goto out; + fdt->open_fds = new_openset; + fdt->close_on_exec = new_execset; + fdt->max_fdset = nfds; + + nfds = NR_OPEN_DEFAULT; + /* + * Expand to the max in easy steps, and keep expanding it until + * we have enough for the requested fd array size. + */ + do { +#if NR_OPEN_DEFAULT < 256 + if (nfds < 256) + nfds = 256; + else +#endif + if (nfds < (PAGE_SIZE / sizeof(struct file *))) + nfds = PAGE_SIZE / sizeof(struct file *); + else { + nfds = nfds * 2; + if (nfds > NR_OPEN) + nfds = NR_OPEN; + } + } while (nfds <= nr); + new_fds = alloc_fd_array(nfds); + if (!new_fds) goto out; + fdt->fd = new_fds; + fdt->max_fds = nfds; + fdt->free_files = NULL; + return fdt; +out: + if (new_openset) + free_fdset(new_openset, nfds); + if (new_execset) + free_fdset(new_execset, nfds); + kfree(fdt); + return NULL; +} - error = 0; - - /* Copy the existing tables and install the new pointers */ +/* + * Expands the file descriptor table - it will allocate a new fdtable and + * both fd array and fdset. It is expected to be called with the + * files_lock held. + */ +static int expand_fdtable(struct files_struct *files, int nr) + __releases(files->file_lock) + __acquires(files->file_lock) +{ + int error = 0; + struct fdtable *fdt; + struct fdtable *nfdt = NULL; + + spin_unlock(&files->file_lock); + nfdt = alloc_fdtable(nr); + if (!nfdt) { + error = -ENOMEM; + spin_lock(&files->file_lock); + goto out; + } + + spin_lock(&files->file_lock); fdt = files_fdtable(files); - if (nfds > fdt->max_fdset) { - int i = fdt->max_fdset / (sizeof(unsigned long) * 8); - int count = (nfds - fdt->max_fdset) / 8; - - /* - * Don't copy the entire array if the current fdset is - * not yet initialised. - */ - if (i) { - memcpy (new_openset, fdt->open_fds, fdt->max_fdset/8); - memcpy (new_execset, fdt->close_on_exec, fdt->max_fdset/8); - memset (&new_openset->fds_bits[i], 0, count); - memset (&new_execset->fds_bits[i], 0, count); - } - - nfds = xchg(&fdt->max_fdset, nfds); - new_openset = xchg(&fdt->open_fds, new_openset); - new_execset = xchg(&fdt->close_on_exec, new_execset); + /* + * Check again since another task may have expanded the + * fd table while we dropped the lock + */ + if (nr >= fdt->max_fds || nr >= fdt->max_fdset) { + copy_fdtable(nfdt, fdt); + } else { + /* Somebody expanded while we dropped file_lock */ spin_unlock(&files->file_lock); - free_fdset (new_openset, nfds); - free_fdset (new_execset, nfds); + __free_fdtable(nfdt); spin_lock(&files->file_lock); - return 0; - } - /* Somebody expanded the array while we slept ... */ - + goto out; + } + rcu_assign_pointer(files->fdt, nfdt); + free_fdtable(fdt); out: - spin_unlock(&files->file_lock); - if (new_openset) - free_fdset(new_openset, nfds); - if (new_execset) - free_fdset(new_execset, nfds); - spin_lock(&files->file_lock); return error; } @@ -246,17 +354,36 @@ int expand_files(struct files_struct *files, int nr) struct fdtable *fdt; fdt = files_fdtable(files); - if (nr >= fdt->max_fdset) { - expand = 1; - if ((err = expand_fdset(files, nr))) + if (nr >= fdt->max_fdset || nr >= fdt->max_fds) { + if (fdt->max_fdset >= NR_OPEN || + fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) { + err = -EMFILE; goto out; - } - if (nr >= fdt->max_fds) { + } expand = 1; - if ((err = expand_fd_array(files, nr))) + if ((err = expand_fdtable(files, nr))) goto out; } err = expand; out: return err; } + +static void __devinit fdtable_defer_list_init(int cpu) +{ + struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu); + spin_lock_init(&fddef->lock); + INIT_WORK(&fddef->wq, (void (*)(void *))free_fdtable_work, fddef); + init_timer(&fddef->timer); + fddef->timer.data = (unsigned long)fddef; + fddef->timer.function = fdtable_timer; + fddef->next = NULL; +} + +void __init files_defer_init(void) +{ + int i; + /* Really early - can't use for_each_cpu */ + for (i = 0; i < NR_CPUS; i++) + fdtable_defer_list_init(i); +} diff --git a/fs/file_table.c b/fs/file_table.c index 43e9e1737de2c..86ec8ae985b41 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -14,6 +14,7 @@ #include <linux/fs.h> #include <linux/security.h> #include <linux/eventpoll.h> +#include <linux/rcupdate.h> #include <linux/mount.h> #include <linux/cdev.h> #include <linux/fsnotify.h> @@ -53,11 +54,17 @@ void filp_dtor(void * objp, struct kmem_cache_s *cachep, unsigned long dflags) spin_unlock_irqrestore(&filp_count_lock, flags); } -static inline void file_free(struct file *f) +static inline void file_free_rcu(struct rcu_head *head) { + struct file *f = container_of(head, struct file, f_rcuhead); kmem_cache_free(filp_cachep, f); } +static inline void file_free(struct file *f) +{ + call_rcu(&f->f_rcuhead, file_free_rcu); +} + /* Find an unused file structure and return a pointer to it. * Returns NULL, if there are no more free file structures or * we run out of memory. @@ -110,7 +117,7 @@ EXPORT_SYMBOL(get_empty_filp); void fastcall fput(struct file *file) { - if (atomic_dec_and_test(&file->f_count)) + if (rcuref_dec_and_test(&file->f_count)) __fput(file); } @@ -156,11 +163,17 @@ struct file fastcall *fget(unsigned int fd) struct file *file; struct files_struct *files = current->files; - spin_lock(&files->file_lock); + rcu_read_lock(); file = fcheck_files(files, fd); - if (file) - get_file(file); - spin_unlock(&files->file_lock); + if (file) { + if (!rcuref_inc_lf(&file->f_count)) { + /* File object ref couldn't be taken */ + rcu_read_unlock(); + return NULL; + } + } + rcu_read_unlock(); + return file; } @@ -182,21 +195,25 @@ struct file fastcall *fget_light(unsigned int fd, int *fput_needed) if (likely((atomic_read(&files->count) == 1))) { file = fcheck_files(files, fd); } else { - spin_lock(&files->file_lock); + rcu_read_lock(); file = fcheck_files(files, fd); if (file) { - get_file(file); - *fput_needed = 1; + if (rcuref_inc_lf(&file->f_count)) + *fput_needed = 1; + else + /* Didn't get the reference, someone's freed */ + file = NULL; } - spin_unlock(&files->file_lock); + rcu_read_unlock(); } + return file; } void put_filp(struct file *file) { - if (atomic_dec_and_test(&file->f_count)) { + if (rcuref_dec_and_test(&file->f_count)) { security_file_free(file); file_kill(file); file_free(file); @@ -257,4 +274,5 @@ void __init files_init(unsigned long mempages) files_stat.max_files = n; if (files_stat.max_files < NR_FILE) files_stat.max_files = NR_FILE; + files_defer_init(); } diff --git a/fs/open.c b/fs/open.c index b6542516a0cab..2fac58c51910c 100644 --- a/fs/open.c +++ b/fs/open.c @@ -24,6 +24,7 @@ #include <linux/personality.h> #include <linux/pagemap.h> #include <linux/syscalls.h> +#include <linux/rcupdate.h> #include <asm/unistd.h> @@ -930,9 +931,8 @@ void fastcall fd_install(unsigned int fd, struct file * file) struct fdtable *fdt; spin_lock(&files->file_lock); fdt = files_fdtable(files); - if (unlikely(fdt->fd[fd] != NULL)) - BUG(); - fdt->fd[fd] = file; + BUG_ON(fdt->fd[fd] != NULL); + rcu_assign_pointer(fdt->fd[fd], file); spin_unlock(&files->file_lock); } @@ -1024,7 +1024,7 @@ asmlinkage long sys_close(unsigned int fd) filp = fdt->fd[fd]; if (!filp) goto out_unlock; - fdt->fd[fd] = NULL; + rcu_assign_pointer(fdt->fd[fd], NULL); FD_CLR(fd, fdt->close_on_exec); __put_unused_fd(files, fd); spin_unlock(&files->file_lock); diff --git a/include/linux/file.h b/include/linux/file.h index db372230848ed..f5bbd4c508b3d 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -9,6 +9,7 @@ #include <linux/posix_types.h> #include <linux/compiler.h> #include <linux/spinlock.h> +#include <linux/rcupdate.h> /* * The default fd array needs to be at least BITS_PER_LONG, @@ -23,6 +24,9 @@ struct fdtable { struct file ** fd; /* current fd array */ fd_set *close_on_exec; fd_set *open_fds; + struct rcu_head rcu; + struct files_struct *free_files; + struct fdtable *next; }; /* @@ -31,13 +35,14 @@ struct fdtable { struct files_struct { atomic_t count; spinlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */ + struct fdtable *fdt; struct fdtable fdtab; fd_set close_on_exec_init; fd_set open_fds_init; struct file * fd_array[NR_OPEN_DEFAULT]; }; -#define files_fdtable(files) (&(files)->fdtab) +#define files_fdtable(files) (rcu_dereference((files)->fdt)) extern void FASTCALL(__fput(struct file *)); extern void FASTCALL(fput(struct file *)); @@ -65,6 +70,8 @@ extern fd_set *alloc_fdset(int); extern void free_fdset(fd_set *, int); extern int expand_files(struct files_struct *, int nr); +extern void free_fdtable(struct fdtable *fdt); +extern void __init files_defer_init(void); static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) { @@ -72,7 +79,7 @@ static inline struct file * fcheck_files(struct files_struct *files, unsigned in struct fdtable *fdt = files_fdtable(files); if (fd < fdt->max_fds) - file = fdt->fd[fd]; + file = rcu_dereference(fdt->fd[fd]); return file; } diff --git a/include/linux/fs.h b/include/linux/fs.h index fd93ab7da9050..7f61227827d76 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -9,6 +9,7 @@ #include <linux/config.h> #include <linux/limits.h> #include <linux/ioctl.h> +#include <linux/rcuref.h> /* * It's silly to have NR_OPEN bigger than NR_FILE, but you can change @@ -597,12 +598,13 @@ struct file { spinlock_t f_ep_lock; #endif /* #ifdef CONFIG_EPOLL */ struct address_space *f_mapping; + struct rcu_head f_rcuhead; }; extern spinlock_t files_lock; #define file_list_lock() spin_lock(&files_lock); #define file_list_unlock() spin_unlock(&files_lock); -#define get_file(x) atomic_inc(&(x)->f_count) +#define get_file(x) rcuref_inc(&(x)->f_count) #define file_count(x) atomic_read(&(x)->f_count) #define MAX_NON_LFS ((1UL<<31) - 1) diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 94aefa54a1b5f..68ab5f2ab9cdb 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -2,6 +2,7 @@ #define _LINUX__INIT_TASK_H #include <linux/file.h> +#include <linux/rcupdate.h> #define INIT_FDTABLE \ { \ @@ -11,12 +12,16 @@ .fd = &init_files.fd_array[0], \ .close_on_exec = &init_files.close_on_exec_init, \ .open_fds = &init_files.open_fds_init, \ + .rcu = RCU_HEAD_INIT, \ + .free_files = NULL, \ + .next = NULL, \ } #define INIT_FILES \ { \ .count = ATOMIC_INIT(1), \ .file_lock = SPIN_LOCK_UNLOCKED, \ + .fdt = &init_files.fdtab, \ .fdtab = INIT_FDTABLE, \ .close_on_exec_init = { { 0, } }, \ .open_fds_init = { { 0, } }, \ diff --git a/kernel/exit.c b/kernel/exit.c index 83beb1e93b18c..6d2089a1bce74 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -411,15 +411,16 @@ void fastcall put_files_struct(struct files_struct *files) close_files(files); /* * Free the fd and fdset arrays if we expanded them. + * If the fdtable was embedded, pass files for freeing + * at the end of the RCU grace period. Otherwise, + * you can free files immediately. */ fdt = files_fdtable(files); - if (fdt->fd != &files->fd_array[0]) - free_fd_array(fdt->fd, fdt->max_fds); - if (fdt->max_fdset > __FD_SETSIZE) { - free_fdset(fdt->open_fds, fdt->max_fdset); - free_fdset(fdt->close_on_exec, fdt->max_fdset); - } - kmem_cache_free(files_cachep, files); + if (fdt == &files->fdtab) + fdt->free_files = files; + else + kmem_cache_free(files_cachep, files); + free_fdtable(fdt); } } diff --git a/kernel/fork.c b/kernel/fork.c index ecc694debb50c..8149f3602881d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -35,6 +35,7 @@ #include <linux/syscalls.h> #include <linux/jiffies.h> #include <linux/futex.h> +#include <linux/rcupdate.h> #include <linux/ptrace.h> #include <linux/mount.h> #include <linux/audit.h> @@ -565,13 +566,12 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk) return 0; } -static int count_open_files(struct files_struct *files, int size) +static int count_open_files(struct fdtable *fdt) { + int size = fdt->max_fdset; int i; - struct fdtable *fdt; /* Find the last open fd */ - fdt = files_fdtable(files); for (i = size/(8*sizeof(long)); i > 0; ) { if (fdt->open_fds->fds_bits[--i]) break; @@ -592,13 +592,17 @@ static struct files_struct *alloc_files(void) atomic_set(&newf->count, 1); spin_lock_init(&newf->file_lock); - fdt = files_fdtable(newf); + fdt = &newf->fdtab; fdt->next_fd = 0; fdt->max_fds = NR_OPEN_DEFAULT; fdt->max_fdset = __FD_SETSIZE; fdt->close_on_exec = &newf->close_on_exec_init; fdt->open_fds = &newf->open_fds_init; fdt->fd = &newf->fd_array[0]; + INIT_RCU_HEAD(&fdt->rcu); + fdt->free_files = NULL; + fdt->next = NULL; + rcu_assign_pointer(newf->fdt, fdt); out: return newf; } @@ -637,7 +641,7 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) old_fdt = files_fdtable(oldf); new_fdt = files_fdtable(newf); size = old_fdt->max_fdset; - open_files = count_open_files(oldf, old_fdt->max_fdset); + open_files = count_open_files(old_fdt); expand = 0; /* @@ -661,7 +665,14 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) spin_unlock(&newf->file_lock); if (error < 0) goto out_release; + new_fdt = files_fdtable(newf); + /* + * Reacquire the oldf lock and a pointer to its fd table + * who knows it may have a new bigger fd table. We need + * the latest pointer. + */ spin_lock(&oldf->file_lock); + old_fdt = files_fdtable(oldf); } old_fds = old_fdt->fd; @@ -683,7 +694,7 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) */ FD_CLR(open_files - i, new_fdt->open_fds); } - *new_fds++ = f; + rcu_assign_pointer(*new_fds++, f); } spin_unlock(&oldf->file_lock); -- GitLab From b835996f628eadb55c5fb222ba46fe9395bf73c7 Mon Sep 17 00:00:00 2001 From: Dipankar Sarma <dipankar@in.ibm.com> Date: Fri, 9 Sep 2005 13:04:14 -0700 Subject: [PATCH 205/563] [PATCH] files: lock-free fd look-up With the use of RCU in files structure, the look-up of files using fds can now be lock-free. The lookup is protected by rcu_read_lock()/rcu_read_unlock(). This patch changes the readers to use lock-free lookup. Signed-off-by: Maneesh Soni <maneesh@in.ibm.com> Signed-off-by: Ravikiran Thirumalai <kiran_th@gmail.com> Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/mips/kernel/irixioctl.c | 5 +++-- arch/sparc64/solaris/ioctl.c | 7 ++++--- drivers/char/tty_io.c | 4 ++-- fs/fcntl.c | 4 ++-- fs/proc/base.c | 29 +++++++++++++++-------------- fs/select.c | 13 ++++++++++--- net/ipv4/netfilter/ipt_owner.c | 1 + net/ipv6/netfilter/ip6t_owner.c | 1 + security/selinux/hooks.c | 2 +- 9 files changed, 39 insertions(+), 27 deletions(-) diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c index 4cd3d38a22c25..3cdc22346f4c7 100644 --- a/arch/mips/kernel/irixioctl.c +++ b/arch/mips/kernel/irixioctl.c @@ -14,6 +14,7 @@ #include <linux/syscalls.h> #include <linux/tty.h> #include <linux/file.h> +#include <linux/rcupdate.h> #include <asm/uaccess.h> #include <asm/ioctl.h> @@ -33,7 +34,7 @@ static struct tty_struct *get_tty(int fd) struct file *filp; struct tty_struct *ttyp = NULL; - spin_lock(¤t->files->file_lock); + rcu_read_lock(); filp = fcheck(fd); if(filp && filp->private_data) { ttyp = (struct tty_struct *) filp->private_data; @@ -41,7 +42,7 @@ static struct tty_struct *get_tty(int fd) if(ttyp->magic != TTY_MAGIC) ttyp =NULL; } - spin_unlock(¤t->files->file_lock); + rcu_read_unlock(); return ttyp; } diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c index 374766455f5e2..be0a054e3ed6b 100644 --- a/arch/sparc64/solaris/ioctl.c +++ b/arch/sparc64/solaris/ioctl.c @@ -24,6 +24,7 @@ #include <linux/netdevice.h> #include <linux/mtio.h> #include <linux/time.h> +#include <linux/rcupdate.h> #include <linux/compat.h> #include <net/sock.h> @@ -295,16 +296,16 @@ static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg) struct inode *ino; struct fdtable *fdt; /* I wonder which of these tests are superfluous... --patrik */ - spin_lock(¤t->files->file_lock); + rcu_read_lock(); fdt = files_fdtable(current->files); if (! fdt->fd[fd] || ! fdt->fd[fd]->f_dentry || ! (ino = fdt->fd[fd]->f_dentry->d_inode) || ! S_ISSOCK(ino->i_mode)) { - spin_unlock(¤t->files->file_lock); + rcu_read_unlock(); return TBADF; } - spin_unlock(¤t->files->file_lock); + rcu_read_unlock(); switch (cmd & 0xff) { case 109: /* SI_SOCKPARAMS */ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 0bfc7af689172..e5953f3433f3e 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2480,7 +2480,7 @@ static void __do_SAK(void *arg) } task_lock(p); if (p->files) { - spin_lock(&p->files->file_lock); + rcu_read_lock(); fdt = files_fdtable(p->files); for (i=0; i < fdt->max_fds; i++) { filp = fcheck_files(p->files, i); @@ -2495,7 +2495,7 @@ static void __do_SAK(void *arg) break; } } - spin_unlock(&p->files->file_lock); + rcu_read_unlock(); } task_unlock(p); } while_each_task_pid(session, PIDTYPE_SID, p); diff --git a/fs/fcntl.c b/fs/fcntl.c index d2f3ed8acd932..863b46e0d78a6 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -40,10 +40,10 @@ static inline int get_close_on_exec(unsigned int fd) struct files_struct *files = current->files; struct fdtable *fdt; int res; - spin_lock(&files->file_lock); + rcu_read_lock(); fdt = files_fdtable(files); res = FD_ISSET(fd, fdt->close_on_exec); - spin_unlock(&files->file_lock); + rcu_read_unlock(); return res; } diff --git a/fs/proc/base.c b/fs/proc/base.c index d0087a0b024be..23db452ab428c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -62,6 +62,7 @@ #include <linux/namespace.h> #include <linux/mm.h> #include <linux/smp_lock.h> +#include <linux/rcupdate.h> #include <linux/kallsyms.h> #include <linux/mount.h> #include <linux/security.h> @@ -283,16 +284,16 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm files = get_files_struct(task); if (files) { - spin_lock(&files->file_lock); + rcu_read_lock(); file = fcheck_files(files, fd); if (file) { *mnt = mntget(file->f_vfsmnt); *dentry = dget(file->f_dentry); - spin_unlock(&files->file_lock); + rcu_read_unlock(); put_files_struct(files); return 0; } - spin_unlock(&files->file_lock); + rcu_read_unlock(); put_files_struct(files); } return -ENOENT; @@ -1062,7 +1063,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) files = get_files_struct(p); if (!files) goto out; - spin_lock(&files->file_lock); + rcu_read_lock(); fdt = files_fdtable(files); for (fd = filp->f_pos-2; fd < fdt->max_fds; @@ -1071,7 +1072,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) if (!fcheck_files(files, fd)) continue; - spin_unlock(&files->file_lock); + rcu_read_unlock(); j = NUMBUF; i = fd; @@ -1083,12 +1084,12 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) ino = fake_ino(tid, PROC_TID_FD_DIR + fd); if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) { - spin_lock(&files->file_lock); + rcu_read_lock(); break; } - spin_lock(&files->file_lock); + rcu_read_lock(); } - spin_unlock(&files->file_lock); + rcu_read_unlock(); put_files_struct(files); } out: @@ -1263,9 +1264,9 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) files = get_files_struct(task); if (files) { - spin_lock(&files->file_lock); + rcu_read_lock(); if (fcheck_files(files, fd)) { - spin_unlock(&files->file_lock); + rcu_read_unlock(); put_files_struct(files); if (task_dumpable(task)) { inode->i_uid = task->euid; @@ -1277,7 +1278,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) security_task_to_inode(task, inode); return 1; } - spin_unlock(&files->file_lock); + rcu_read_unlock(); put_files_struct(files); } d_drop(dentry); @@ -1369,7 +1370,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, if (!files) goto out_unlock; inode->i_mode = S_IFLNK; - spin_lock(&files->file_lock); + rcu_read_lock(); file = fcheck_files(files, fd); if (!file) goto out_unlock2; @@ -1377,7 +1378,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, inode->i_mode |= S_IRUSR | S_IXUSR; if (file->f_mode & 2) inode->i_mode |= S_IWUSR | S_IXUSR; - spin_unlock(&files->file_lock); + rcu_read_unlock(); put_files_struct(files); inode->i_op = &proc_pid_link_inode_operations; inode->i_size = 64; @@ -1387,7 +1388,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, return NULL; out_unlock2: - spin_unlock(&files->file_lock); + rcu_read_unlock(); put_files_struct(files); out_unlock: iput(inode); diff --git a/fs/select.c b/fs/select.c index 2e56325c73c47..f10a10317d549 100644 --- a/fs/select.c +++ b/fs/select.c @@ -22,6 +22,7 @@ #include <linux/personality.h> /* for STICKY_TIMEOUTS */ #include <linux/file.h> #include <linux/fs.h> +#include <linux/rcupdate.h> #include <asm/uaccess.h> @@ -185,9 +186,9 @@ int do_select(int n, fd_set_bits *fds, long *timeout) int retval, i; long __timeout = *timeout; - spin_lock(¤t->files->file_lock); + rcu_read_lock(); retval = max_select_fd(n, fds); - spin_unlock(¤t->files->file_lock); + rcu_read_unlock(); if (retval < 0) return retval; @@ -329,8 +330,10 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s goto out_nofds; /* max_fdset can increase, so grab it once to avoid race */ + rcu_read_lock(); fdt = files_fdtable(current->files); max_fdset = fdt->max_fdset; + rcu_read_unlock(); if (n > max_fdset) n = max_fdset; @@ -469,10 +472,14 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti struct poll_list *head; struct poll_list *walk; struct fdtable *fdt; + int max_fdset; /* Do a sanity check on nfds ... */ + rcu_read_lock(); fdt = files_fdtable(current->files); - if (nfds > fdt->max_fdset && nfds > OPEN_MAX) + max_fdset = fdt->max_fdset; + rcu_read_unlock(); + if (nfds > max_fdset && nfds > OPEN_MAX) return -EINVAL; if (timeout) { diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c index c1889f88262b4..0cee2862ed85f 100644 --- a/net/ipv4/netfilter/ipt_owner.c +++ b/net/ipv4/netfilter/ipt_owner.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/skbuff.h> #include <linux/file.h> +#include <linux/rcupdate.h> #include <net/sock.h> #include <linux/netfilter_ipv4/ipt_owner.h> diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c index 9b91decbfddba..4de4cdad4b7d2 100644 --- a/net/ipv6/netfilter/ip6t_owner.c +++ b/net/ipv6/netfilter/ip6t_owner.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/skbuff.h> #include <linux/file.h> +#include <linux/rcupdate.h> #include <net/sock.h> #include <linux/netfilter_ipv6/ip6t_owner.h> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index acb5a495a902f..f40c8221ec1ba 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1652,7 +1652,7 @@ static inline void flush_unauthorized_files(struct files_struct * files) continue; } if (devnull) { - atomic_inc(&devnull->f_count); + rcuref_inc(&devnull->f_count); } else { devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR); if (!devnull) { -- GitLab From 2822541893d88f84dd4f1525108d73effecd9d39 Mon Sep 17 00:00:00 2001 From: Dipankar Sarma <dipankar@in.ibm.com> Date: Fri, 9 Sep 2005 13:04:15 -0700 Subject: [PATCH 206/563] [PATCH] files: files locking doc Add documentation describing the new locking scheme for file descriptor table. Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/filesystems/files.txt | 123 ++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 Documentation/filesystems/files.txt diff --git a/Documentation/filesystems/files.txt b/Documentation/filesystems/files.txt new file mode 100644 index 0000000000000..8c206f4e02508 --- /dev/null +++ b/Documentation/filesystems/files.txt @@ -0,0 +1,123 @@ +File management in the Linux kernel +----------------------------------- + +This document describes how locking for files (struct file) +and file descriptor table (struct files) works. + +Up until 2.6.12, the file descriptor table has been protected +with a lock (files->file_lock) and reference count (files->count). +->file_lock protected accesses to all the file related fields +of the table. ->count was used for sharing the file descriptor +table between tasks cloned with CLONE_FILES flag. Typically +this would be the case for posix threads. As with the common +refcounting model in the kernel, the last task doing +a put_files_struct() frees the file descriptor (fd) table. +The files (struct file) themselves are protected using +reference count (->f_count). + +In the new lock-free model of file descriptor management, +the reference counting is similar, but the locking is +based on RCU. The file descriptor table contains multiple +elements - the fd sets (open_fds and close_on_exec, the +array of file pointers, the sizes of the sets and the array +etc.). In order for the updates to appear atomic to +a lock-free reader, all the elements of the file descriptor +table are in a separate structure - struct fdtable. +files_struct contains a pointer to struct fdtable through +which the actual fd table is accessed. Initially the +fdtable is embedded in files_struct itself. On a subsequent +expansion of fdtable, a new fdtable structure is allocated +and files->fdtab points to the new structure. The fdtable +structure is freed with RCU and lock-free readers either +see the old fdtable or the new fdtable making the update +appear atomic. Here are the locking rules for +the fdtable structure - + +1. All references to the fdtable must be done through + the files_fdtable() macro : + + struct fdtable *fdt; + + rcu_read_lock(); + + fdt = files_fdtable(files); + .... + if (n <= fdt->max_fds) + .... + ... + rcu_read_unlock(); + + files_fdtable() uses rcu_dereference() macro which takes care of + the memory barrier requirements for lock-free dereference. + The fdtable pointer must be read within the read-side + critical section. + +2. Reading of the fdtable as described above must be protected + by rcu_read_lock()/rcu_read_unlock(). + +3. For any update to the the fd table, files->file_lock must + be held. + +4. To look up the file structure given an fd, a reader + must use either fcheck() or fcheck_files() APIs. These + take care of barrier requirements due to lock-free lookup. + An example : + + struct file *file; + + rcu_read_lock(); + file = fcheck(fd); + if (file) { + ... + } + .... + rcu_read_unlock(); + +5. Handling of the file structures is special. Since the look-up + of the fd (fget()/fget_light()) are lock-free, it is possible + that look-up may race with the last put() operation on the + file structure. This is avoided using the rcuref APIs + on ->f_count : + + rcu_read_lock(); + file = fcheck_files(files, fd); + if (file) { + if (rcuref_inc_lf(&file->f_count)) + *fput_needed = 1; + else + /* Didn't get the reference, someone's freed */ + file = NULL; + } + rcu_read_unlock(); + .... + return file; + + rcuref_inc_lf() detects if refcounts is already zero or + goes to zero during increment. If it does, we fail + fget()/fget_light(). + +6. Since both fdtable and file structures can be looked up + lock-free, they must be installed using rcu_assign_pointer() + API. If they are looked up lock-free, rcu_dereference() + must be used. However it is advisable to use files_fdtable() + and fcheck()/fcheck_files() which take care of these issues. + +7. While updating, the fdtable pointer must be looked up while + holding files->file_lock. If ->file_lock is dropped, then + another thread expand the files thereby creating a new + fdtable and making the earlier fdtable pointer stale. + For example : + + spin_lock(&files->file_lock); + fd = locate_fd(files, file, start); + if (fd >= 0) { + /* locate_fd() may have expanded fdtable, load the ptr */ + fdt = files_fdtable(files); + FD_SET(fd, fdt->open_fds); + FD_CLR(fd, fdt->close_on_exec); + spin_unlock(&files->file_lock); + ..... + + Since locate_fd() can drop ->file_lock (and reacquire ->file_lock), + the fdtable pointer (fdt) must be loaded after locate_fd(). + -- GitLab From 93fa58cb831337fdf5d36b3b913441100a484dae Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:18 -0700 Subject: [PATCH 207/563] [PATCH] v9fs: Documentation, Makefiles, Configuration OVERVIEW V9FS is a distributed file system for Linux which provides an implementation of the Plan 9 resource sharing protocol 9P. It can be used to share all sorts of resources: static files, synthetic file servers (such as /proc or /sys), devices, and application file servers (such as FUSE). BACKGROUND Plan 9 (http://plan9.bell-labs.com/plan9) is a research operating system and associated applications suite developed by the Computing Science Research Center of AT&T Bell Laboratories (now a part of Lucent Technologies), the same group that developed UNIX , C, and C++. Plan 9 was initially released in 1993 to universities, and then made generally available in 1995. Its core operating systems code laid the foundation for the Inferno Operating System released as a product by Lucent Bell-Labs in 1997. The Inferno venture was the only commercial embodiment of Plan 9 and is currently maintained as a product by Vita Nuova (http://www.vitanuova.com). After updated releases in 2000 and 2002, Plan 9 was open-sourced under the OSI approved Lucent Public License in 2003. The Plan 9 project was started by Ken Thompson and Rob Pike in 1985. Their intent was to explore potential solutions to some of the shortcomings of UNIX in the face of the widespread use of high-speed networks to connect machines. In UNIX, networking was an afterthought and UNIX clusters became little more than a network of stand-alone systems. Plan 9 was designed from first principles as a seamless distributed system with integrated secure network resource sharing. Applications and services were architected in such a way as to allow for implicit distribution across a cluster of systems. Configuring an environment to use remote application components or services in place of their local equivalent could be achieved with a few simple command line instructions. For the most part, application implementations operated independent of the location of their actual resources. Commercial operating systems haven't changed much in the 20 years since Plan 9 was conceived. Network and distributed systems support is provided by a patchwork of middle-ware, with an endless number of packages supplying pieces of the puzzle. Matters are complicated by the use of different complicated protocols for individual services, and separate implementations for kernel and application resources. The V9FS project (http://v9fs.sourceforge.net) is an attempt to bring Plan 9's unified approach to resource sharing to Linux and other operating systems via support for the 9P2000 resource sharing protocol. V9FS HISTORY V9FS was originally developed by Ron Minnich and Maya Gokhale at Los Alamos National Labs (LANL) in 1997. In November of 2001, Greg Watson setup a SourceForge project as a public repository for the code which supported the Linux 2.4 kernel. About a year ago, I picked up the initial attempt Ron Minnich had made to provide 2.6 support and got the code integrated into a 2.6.5 kernel. I then went through a line-for-line re-write attempting to clean-up the code while more closely following the Linux Kernel style guidelines. I co-authored a paper with Ron Minnich on the V9FS Linux support including performance comparisons to NFSv3 using Bonnie and PostMark - this paper appeared at the USENIX/FREENIX 2005 conference in April 2005: ( http://www.usenix.org/events/usenix05/tech/freenix/hensbergen.html ). CALL FOR PARTICIPATION/REQUEST FOR COMMENTS Our 2.6 kernel support is stabilizing and we'd like to begin pursuing its integration into the official kernel tree. We would appreciate any review, comments, critiques, and additions from this community and are actively seeking people to join our project and help us produce something that would be acceptable and useful to the Linux community. STATUS The code is reasonably stable, although there are no doubt corner cases our regression tests haven't discovered yet. It is in regular use by several of the developers and has been tested on x86 and PowerPC (32-bit and 64-bit) in both small and large (LANL cluster) deployments. Our current regression tests include fsx, bonnie, and postmark. It was our intention to keep things as simple as possible for this release -- trying to focus on correctness within the core of the protocol support versus a rich set of features. For example: a more complete security model and cache layer are in the road map, but excluded from this release. Additionally, we have removed support for mmap operations at Al Viro's request. PERFORMANCE Detailed performance numbers and analysis are included in the FREENIX paper, but we show comparable performance to NFSv3 for large file operations based on the Bonnie benchmark, and superior performance for many small file operations based on the PostMark benchmark. Somewhat preliminary graphs (from the FREENIX paper) are available (http://v9fs.sourceforge.net/perf/index.html). RESOURCES The source code is available in a few different forms: tarballs: http://v9fs.sf.net CVSweb: http://cvs.sourceforge.net/viewcvs.py/v9fs/linux-9p/ CVS: :pserver:anonymous@cvs.sourceforge.net:/cvsroot/v9fs/linux-9p Git: rsync://v9fs.graverobber.org/v9fs (webgit: http://v9fs.graverobber.org) 9P: tcp!v9fs.graverobber.org!6564 The user-level server is available from either the Plan 9 distribution or from http://v9fs.sf.net Other support applications are still being developed, but preliminary version can be downloaded from sourceforge. Documentation on the protocol has historically been the Plan 9 Man pages (http://plan9.bell-labs.com/sys/man/5/INDEX.html), but there is an effort under way to write a more complete Internet-Draft style specification (http://v9fs.sf.net/rfc). There are a couple of mailing lists supporting v9fs, but the most used is v9fs-developer@lists.sourceforge.net -- please direct/cc your comments there so the other v9fs contibutors can participate in the conversation. There is also an IRC channel: irc://freenode.net/#v9fs This part of the patch contains Documentation, Makefiles, and configuration file changes. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/filesystems/v9fs.txt | 95 ++++++++++++++++++++++++++++++ MAINTAINERS | 11 ++++ fs/9p/Makefile | 17 ++++++ fs/Kconfig | 11 ++++ fs/Makefile | 1 + 5 files changed, 135 insertions(+) create mode 100644 Documentation/filesystems/v9fs.txt create mode 100644 fs/9p/Makefile diff --git a/Documentation/filesystems/v9fs.txt b/Documentation/filesystems/v9fs.txt new file mode 100644 index 0000000000000..4e92feb6b5078 --- /dev/null +++ b/Documentation/filesystems/v9fs.txt @@ -0,0 +1,95 @@ + V9FS: 9P2000 for Linux + ====================== + +ABOUT +===== + +v9fs is a Unix implementation of the Plan 9 9p remote filesystem protocol. + +This software was originally developed by Ron Minnich <rminnich@lanl.gov> +and Maya Gokhale <maya@lanl.gov>. Additional development by Greg Watson +<gwatson@lanl.gov> and most recently Eric Van Hensbergen +<ericvh@gmail.com> and Latchesar Ionkov <lucho@ionkov.net>. + +USAGE +===== + +For remote file server: + + mount -t 9P 10.10.1.2 /mnt/9 + +For Plan 9 From User Space applications (http://swtch.com/plan9) + + mount -t 9P `namespace`/acme /mnt/9 -o proto=unix,name=$USER + +OPTIONS +======= + + proto=name select an alternative transport. Valid options are + currently: + unix - specifying a named pipe mount point + tcp - specifying a normal TCP/IP connection + fd - used passed file descriptors for connection + (see rfdno and wfdno) + + name=name user name to attempt mount as on the remote server. The + server may override or ignore this value. Certain user + names may require authentication. + + aname=name aname specifies the file tree to access when the server is + offering several exported file systems. + + debug=n specifies debug level. The debug level is a bitmask. + 0x01 = display verbose error messages + 0x02 = developer debug (DEBUG_CURRENT) + 0x04 = display 9P trace + 0x08 = display VFS trace + 0x10 = display Marshalling debug + 0x20 = display RPC debug + 0x40 = display transport debug + 0x80 = display allocation debug + + rfdno=n the file descriptor for reading with proto=fd + + wfdno=n the file descriptor for writing with proto=fd + + maxdata=n the number of bytes to use for 9P packet payload (msize) + + port=n port to connect to on the remote server + + timeout=n request timeouts (in ms) (default 60000ms) + + noextend force legacy mode (no 9P2000.u semantics) + + uid attempt to mount as a particular uid + + gid attempt to mount with a particular gid + + afid security channel - used by Plan 9 authentication protocols + + nodevmap do not map special files - represent them as normal files. + This can be used to share devices/named pipes/sockets between + hosts. This functionality will be expanded in later versions. + +RESOURCES +========= + +The Linux version of the 9P server, along with some client-side utilities +can be found at http://v9fs.sf.net (along with a CVS repository of the +development branch of this module). There are user and developer mailing +lists here, as well as a bug-tracker. + +For more information on the Plan 9 Operating System check out +http://plan9.bell-labs.com/plan9 + +For information on Plan 9 from User Space (Plan 9 applications and libraries +ported to Linux/BSD/OSX/etc) check out http://swtch.com/plan9 + + +STATUS +====== + +The 2.6 kernel support is working on PPC and x86. + +PLEASE USE THE SOURCEFORGE BUG-TRACKER TO REPORT PROBLEMS. + diff --git a/MAINTAINERS b/MAINTAINERS index eaa46594f0211..8429bdb1d2a1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2684,6 +2684,17 @@ L: rio500-users@lists.sourceforge.net W: http://rio500.sourceforge.net S: Maintained +V9FS FILE SYSTEM +P: Eric Van Hensbergen +M: ericvh@gmail.com +P: Ron Minnich +M: rminnich@lanl.gov +P: Latchesar Ionkov +M: lucho@ionkov.net +L: v9fs-developer@lists.sourceforge.net +W: http://v9fs.sf.net +S: Maintained + VIDEO FOR LINUX P: Mauro Carvalho Chehab M: mchehab@brturbo.com.br diff --git a/fs/9p/Makefile b/fs/9p/Makefile new file mode 100644 index 0000000000000..e4e4ffe5a7dc5 --- /dev/null +++ b/fs/9p/Makefile @@ -0,0 +1,17 @@ +obj-$(CONFIG_9P_FS) := 9p2000.o + +9p2000-objs := \ + vfs_super.o \ + vfs_inode.o \ + vfs_file.o \ + vfs_dir.o \ + vfs_dentry.o \ + error.o \ + mux.o \ + trans_fd.o \ + trans_sock.o \ + 9p.o \ + conv.o \ + v9fs.o \ + fid.o + diff --git a/fs/Kconfig b/fs/Kconfig index 5e817902cb3b4..443aed4e20671 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1703,6 +1703,17 @@ config AFS_FS config RXRPC tristate +config 9P_FS + tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)" + depends on INET && EXPERIMENTAL + help + If you say Y here, you will get experimental support for + Plan 9 resource sharing via the 9P2000 protocol. + + See <http://v9fs.sf.net> for more information. + + If unsure, say N. + endmenu menu "Partition Types" diff --git a/fs/Makefile b/fs/Makefile index 15158309dee4a..d646502c1efb3 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -94,6 +94,7 @@ obj-$(CONFIG_RELAYFS_FS) += relayfs/ obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ obj-$(CONFIG_JFS_FS) += jfs/ obj-$(CONFIG_XFS_FS) += xfs/ +obj-$(CONFIG_9P_FS) += 9p/ obj-$(CONFIG_AFS_FS) += afs/ obj-$(CONFIG_BEFS_FS) += befs/ obj-$(CONFIG_HOSTFS) += hostfs/ -- GitLab From e69e7fe5b0c86b7271045444a3a681136234c659 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:18 -0700 Subject: [PATCH 208/563] [PATCH] v9fs: VFS file, dentry, and directory operations This part of the patch contains the VFS file, dentry & directory interfaces. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/vfs_dentry.c | 126 ++++++++++++++ fs/9p/vfs_dir.c | 226 +++++++++++++++++++++++++ fs/9p/vfs_file.c | 401 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 753 insertions(+) create mode 100644 fs/9p/vfs_dentry.c create mode 100644 fs/9p/vfs_dir.c create mode 100644 fs/9p/vfs_file.c diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c new file mode 100644 index 0000000000000..306c96741f819 --- /dev/null +++ b/fs/9p/vfs_dentry.c @@ -0,0 +1,126 @@ +/* + * linux/fs/9p/vfs_dentry.c + * + * This file contians vfs dentry ops for the 9P2000 protocol. + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/pagemap.h> +#include <linux/stat.h> +#include <linux/string.h> +#include <linux/smp_lock.h> +#include <linux/inet.h> +#include <linux/namei.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "9p.h" +#include "v9fs_vfs.h" +#include "conv.h" +#include "fid.h" + +/** + * v9fs_dentry_validate - VFS dcache hook to validate cache + * @dentry: dentry that is being validated + * @nd: path data + * + * dcache really shouldn't be used for 9P2000 as at all due to + * potential attached semantics to directory traversal (walk). + * + * FUTURE: look into how to use dcache to allow multi-stage + * walks in Plan 9 & potential for better dcache operation which + * would remain valid for Plan 9 semantics. Older versions + * had validation via stat for those interested. However, since + * stat has the same approximate overhead as walk there really + * is no difference. The only improvement would be from a + * time-decay cache like NFS has and that undermines the + * synchronous nature of 9P2000. + * + */ + +static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd) +{ + struct dentry *dc = current->fs->pwd; + + dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry); + if (v9fs_fid_lookup(dentry, FID_OP)) { + dprintk(DEBUG_VFS, "VALID\n"); + return 1; + } + + while (dc != NULL) { + if (dc == dentry) { + dprintk(DEBUG_VFS, "VALID\n"); + return 1; + } + if (dc == dc->d_parent) + break; + + dc = dc->d_parent; + } + + dprintk(DEBUG_VFS, "INVALID\n"); + return 0; +} + +/** + * v9fs_dentry_release - called when dentry is going to be freed + * @dentry: dentry that is being release + * + */ + +void v9fs_dentry_release(struct dentry *dentry) +{ + dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); + + if (dentry->d_fsdata != NULL) { + struct list_head *fid_list = dentry->d_fsdata; + struct v9fs_fid *temp = NULL; + struct v9fs_fid *current_fid = NULL; + struct v9fs_fcall *fcall = NULL; + + list_for_each_entry_safe(current_fid, temp, fid_list, list) { + if (v9fs_t_clunk + (current_fid->v9ses, current_fid->fid, &fcall)) + dprintk(DEBUG_ERROR, "clunk failed: %s\n", + FCALL_ERROR(fcall)); + + v9fs_put_idpool(current_fid->fid, + ¤t_fid->v9ses->fidpool); + + kfree(fcall); + v9fs_fid_destroy(current_fid); + } + + kfree(dentry->d_fsdata); /* free the list_head */ + } +} + +struct dentry_operations v9fs_dentry_operations = { + .d_revalidate = v9fs_dentry_validate, + .d_release = v9fs_dentry_release, +}; diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c new file mode 100644 index 0000000000000..c478a73841863 --- /dev/null +++ b/fs/9p/vfs_dir.c @@ -0,0 +1,226 @@ +/* + * linux/fs/9p/vfs_dir.c + * + * This file contains vfs directory ops for the 9P2000 protocol. + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/stat.h> +#include <linux/string.h> +#include <linux/smp_lock.h> +#include <linux/inet.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "9p.h" +#include "v9fs_vfs.h" +#include "conv.h" +#include "fid.h" + +/** + * dt_type - return file type + * @mistat: mistat structure + * + */ + +static inline int dt_type(struct v9fs_stat *mistat) +{ + unsigned long perm = mistat->mode; + int rettype = DT_REG; + + if (perm & V9FS_DMDIR) + rettype = DT_DIR; + if (perm & V9FS_DMSYMLINK) + rettype = DT_LNK; + + return rettype; +} + +/** + * v9fs_dir_readdir - read a directory + * @filep: opened file structure + * @dirent: directory structure ??? + * @filldir: function to populate directory structure ??? + * + */ + +static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + struct v9fs_fcall *fcall = NULL; + struct inode *inode = filp->f_dentry->d_inode; + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); + struct v9fs_fid *file = filp->private_data; + unsigned int i, n; + int fid = -1; + int ret = 0; + struct v9fs_stat *mi = NULL; + int over = 0; + + dprintk(DEBUG_VFS, "name %s\n", filp->f_dentry->d_name.name); + + fid = file->fid; + + mi = kmalloc(v9ses->maxdata, GFP_KERNEL); + if (!mi) + return -ENOMEM; + + if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) { + kfree(file->rdir_fcall); + file->rdir_fcall = NULL; + } + + if (file->rdir_fcall) { + n = file->rdir_fcall->params.rread.count; + i = file->rdir_fpos; + while (i < n) { + int s = v9fs_deserialize_stat(v9ses, + file->rdir_fcall->params.rread.data + i, + n - i, mi, v9ses->maxdata); + + if (s == 0) { + dprintk(DEBUG_ERROR, + "error while deserializing mistat\n"); + ret = -EIO; + goto FreeStructs; + } + + over = filldir(dirent, mi->name, strlen(mi->name), + filp->f_pos, v9fs_qid2ino(&mi->qid), + dt_type(mi)); + + if (over) { + file->rdir_fpos = i; + file->rdir_pos = filp->f_pos; + break; + } + + i += s; + filp->f_pos += s; + } + + if (!over) { + kfree(file->rdir_fcall); + file->rdir_fcall = NULL; + } + } + + while (!over) { + ret = v9fs_t_read(v9ses, fid, filp->f_pos, + v9ses->maxdata-V9FS_IOHDRSZ, &fcall); + if (ret < 0) { + dprintk(DEBUG_ERROR, "error while reading: %d: %p\n", + ret, fcall); + goto FreeStructs; + } else if (ret == 0) + break; + + n = ret; + i = 0; + while (i < n) { + int s = v9fs_deserialize_stat(v9ses, + fcall->params.rread.data + i, n - i, mi, + v9ses->maxdata); + + if (s == 0) { + dprintk(DEBUG_ERROR, + "error while deserializing mistat\n"); + return -EIO; + } + + over = filldir(dirent, mi->name, strlen(mi->name), + filp->f_pos, v9fs_qid2ino(&mi->qid), + dt_type(mi)); + + if (over) { + file->rdir_fcall = fcall; + file->rdir_fpos = i; + file->rdir_pos = filp->f_pos; + fcall = NULL; + break; + } + + i += s; + filp->f_pos += s; + } + + kfree(fcall); + } + + FreeStructs: + kfree(fcall); + kfree(mi); + return ret; +} + +/** + * v9fs_dir_release - close a directory + * @inode: inode of the directory + * @filp: file pointer to a directory + * + */ + +int v9fs_dir_release(struct inode *inode, struct file *filp) +{ + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); + struct v9fs_fid *fid = filp->private_data; + int fidnum = -1; + + dprintk(DEBUG_VFS, "inode: %p filp: %p fid: %d\n", inode, filp, + fid->fid); + fidnum = fid->fid; + + filemap_fdatawrite(inode->i_mapping); + filemap_fdatawait(inode->i_mapping); + + if (fidnum >= 0) { + fid->fidopen--; + dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, + fid->fid); + + if (fid->fidopen == 0) { + if (v9fs_t_clunk(v9ses, fidnum, NULL)) + dprintk(DEBUG_ERROR, "clunk failed\n"); + + v9fs_put_idpool(fid->fid, &v9ses->fidpool); + } + + kfree(fid->rdir_fcall); + + filp->private_data = NULL; + v9fs_fid_destroy(fid); + } + + d_drop(filp->f_dentry); + return 0; +} + +struct file_operations v9fs_dir_operations = { + .read = generic_read_dir, + .readdir = v9fs_dir_readdir, + .open = v9fs_file_open, + .release = v9fs_dir_release, +}; diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c new file mode 100644 index 0000000000000..1f8ae7d580abe --- /dev/null +++ b/fs/9p/vfs_file.c @@ -0,0 +1,401 @@ +/* + * linux/fs/9p/vfs_file.c + * + * This file contians vfs file ops for 9P2000. + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/stat.h> +#include <linux/string.h> +#include <linux/smp_lock.h> +#include <linux/inet.h> +#include <linux/version.h> +#include <linux/list.h> +#include <asm/uaccess.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "9p.h" +#include "v9fs_vfs.h" +#include "fid.h" + +/** + * v9fs_file_open - open a file (or directory) + * @inode: inode to be opened + * @file: file being opened + * + */ + +int v9fs_file_open(struct inode *inode, struct file *file) +{ + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); + struct v9fs_fid *v9fid = v9fs_fid_lookup(file->f_dentry, FID_WALK); + struct v9fs_fid *v9newfid = NULL; + struct v9fs_fcall *fcall = NULL; + int open_mode = 0; + unsigned int iounit = 0; + int newfid = -1; + long result = -1; + + dprintk(DEBUG_VFS, "inode: %p file: %p v9fid= %p\n", inode, file, + v9fid); + + if (!v9fid) { + struct dentry *dentry = file->f_dentry; + dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); + + /* XXX - some duplication from lookup, generalize later */ + /* basically vfs_lookup is too heavy weight */ + v9fid = v9fs_fid_lookup(file->f_dentry, FID_OP); + if (!v9fid) + return -EBADF; + + v9fid = v9fs_fid_lookup(dentry->d_parent, FID_WALK); + if (!v9fid) + return -EBADF; + + newfid = v9fs_get_idpool(&v9ses->fidpool); + if (newfid < 0) { + eprintk(KERN_WARNING, "newfid fails!\n"); + return -ENOSPC; + } + + result = + v9fs_t_walk(v9ses, v9fid->fid, newfid, + (char *)file->f_dentry->d_name.name, NULL); + if (result < 0) { + v9fs_put_idpool(newfid, &v9ses->fidpool); + dprintk(DEBUG_ERROR, "rewalk didn't work\n"); + return -EBADF; + } + + v9fid = v9fs_fid_create(dentry); + if (v9fid == NULL) { + dprintk(DEBUG_ERROR, "couldn't insert\n"); + return -ENOMEM; + } + v9fid->fid = newfid; + } + + if (v9fid->fidcreate) { + /* create case */ + newfid = v9fid->fid; + iounit = v9fid->iounit; + v9fid->fidcreate = 0; + } else { + if (!S_ISDIR(inode->i_mode)) + newfid = v9fid->fid; + else { + newfid = v9fs_get_idpool(&v9ses->fidpool); + if (newfid < 0) { + eprintk(KERN_WARNING, "allocation failed\n"); + return -ENOSPC; + } + /* This would be a somewhat critical clone */ + result = + v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, + &fcall); + if (result < 0) { + dprintk(DEBUG_ERROR, "clone error: %s\n", + FCALL_ERROR(fcall)); + kfree(fcall); + return result; + } + + v9newfid = v9fs_fid_create(file->f_dentry); + v9newfid->fid = newfid; + v9newfid->qid = v9fid->qid; + v9newfid->iounit = v9fid->iounit; + v9newfid->fidopen = 0; + v9newfid->fidclunked = 0; + v9newfid->v9ses = v9ses; + v9fid = v9newfid; + kfree(fcall); + } + + /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ + /* translate open mode appropriately */ + open_mode = file->f_flags & 0x3; + + if (file->f_flags & O_EXCL) + open_mode |= V9FS_OEXCL; + + if (v9ses->extended) { + if (file->f_flags & O_TRUNC) + open_mode |= V9FS_OTRUNC; + + if (file->f_flags & O_APPEND) + open_mode |= V9FS_OAPPEND; + } + + result = v9fs_t_open(v9ses, newfid, open_mode, &fcall); + if (result < 0) { + dprintk(DEBUG_ERROR, + "open failed, open_mode 0x%x: %s\n", open_mode, + FCALL_ERROR(fcall)); + kfree(fcall); + return result; + } + + iounit = fcall->params.ropen.iounit; + kfree(fcall); + } + + + file->private_data = v9fid; + + v9fid->rdir_pos = 0; + v9fid->rdir_fcall = NULL; + v9fid->fidopen = 1; + v9fid->filp = file; + v9fid->iounit = iounit; + + return 0; +} + +/** + * v9fs_file_lock - lock a file (or directory) + * @inode: inode to be opened + * @file: file being opened + * + * XXX - this looks like a local only lock, we should extend into 9P + * by using open exclusive + */ + +static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) +{ + int res = 0; + struct inode *inode = filp->f_dentry->d_inode; + + dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); + + /* No mandatory locks */ + if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + return -ENOLCK; + + if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { + filemap_fdatawrite(inode->i_mapping); + filemap_fdatawait(inode->i_mapping); + invalidate_inode_pages(&inode->i_data); + } + + return res; +} + +/** + * v9fs_read - read from a file (internal) + * @filep: file pointer to read + * @data: data buffer to read data into + * @count: size of buffer + * @offset: offset at which to read data + * + */ + +static ssize_t +v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); + struct v9fs_fid *v9f = filp->private_data; + struct v9fs_fcall *fcall = NULL; + int fid = v9f->fid; + int rsize = 0; + int result = 0; + int total = 0; + + dprintk(DEBUG_VFS, "\n"); + + rsize = v9ses->maxdata - V9FS_IOHDRSZ; + if (v9f->iounit != 0 && rsize > v9f->iounit) + rsize = v9f->iounit; + + do { + if (count < rsize) + rsize = count; + + result = v9fs_t_read(v9ses, fid, *offset, rsize, &fcall); + + if (result < 0) { + printk(KERN_ERR "9P2000: v9fs_t_read returned %d\n", + result); + + kfree(fcall); + return total; + } else + *offset += result; + + /* XXX - extra copy */ + memcpy(buffer, fcall->params.rread.data, result); + count -= result; + buffer += result; + total += result; + + kfree(fcall); + + if (result < rsize) + break; + } while (count); + + return total; +} + +/** + * v9fs_file_read - read from a file + * @filep: file pointer to read + * @data: data buffer to read data into + * @count: size of buffer + * @offset: offset at which to read data + * + */ + +static ssize_t +v9fs_file_read(struct file *filp, char __user * data, size_t count, + loff_t * offset) +{ + int retval = -1; + int ret = 0; + char *buffer; + + buffer = kmalloc(count, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + retval = v9fs_read(filp, buffer, count, offset); + if (retval > 0) { + if ((ret = copy_to_user(data, buffer, retval)) != 0) { + dprintk(DEBUG_ERROR, "Problem copying to user %d\n", + ret); + retval = ret; + } + } + + kfree(buffer); + + return retval; +} + +/** + * v9fs_write - write to a file + * @filep: file pointer to write + * @data: data buffer to write data from + * @count: size of buffer + * @offset: offset at which to write data + * + */ + +static ssize_t +v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); + struct v9fs_fid *v9fid = filp->private_data; + struct v9fs_fcall *fcall; + int fid = v9fid->fid; + int result = -EIO; + int rsize = 0; + int total = 0; + + dprintk(DEBUG_VFS, "data %p count %d offset %x\n", buffer, (int)count, + (int)*offset); + rsize = v9ses->maxdata - V9FS_IOHDRSZ; + if (v9fid->iounit != 0 && rsize > v9fid->iounit) + rsize = v9fid->iounit; + + dump_data(buffer, count); + + do { + if (count < rsize) + rsize = count; + + result = + v9fs_t_write(v9ses, fid, *offset, rsize, buffer, &fcall); + if (result < 0) { + eprintk(KERN_ERR, "error while writing: %s(%d)\n", + FCALL_ERROR(fcall), result); + kfree(fcall); + return result; + } else + *offset += result; + + kfree(fcall); + + if (result != rsize) { + eprintk(KERN_ERR, + "short write: v9fs_t_write returned %d\n", + result); + break; + } + + count -= result; + buffer += result; + total += result; + } while (count); + + return total; +} + +/** + * v9fs_file_write - write to a file + * @filep: file pointer to write + * @data: data buffer to write data from + * @count: size of buffer + * @offset: offset at which to write data + * + */ + +static ssize_t +v9fs_file_write(struct file *filp, const char __user * data, + size_t count, loff_t * offset) +{ + int ret = -1; + char *buffer; + + buffer = kmalloc(count, GFP_KERNEL); + if (buffer == NULL) + return -ENOMEM; + + ret = copy_from_user(buffer, data, count); + if (ret) { + dprintk(DEBUG_ERROR, "Problem copying from user\n"); + ret = -EFAULT; + } else { + ret = v9fs_write(filp, buffer, count, offset); + } + + kfree(buffer); + + return ret; +} + +struct file_operations v9fs_file_operations = { + .llseek = generic_file_llseek, + .read = v9fs_file_read, + .write = v9fs_file_write, + .open = v9fs_file_open, + .release = v9fs_dir_release, + .lock = v9fs_file_lock, +}; -- GitLab From 2bad8471511ce5cc3ea90d0940622bd4b56b9cce Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:19 -0700 Subject: [PATCH 209/563] [PATCH] v9fs: VFS inode operations This part of the patch contains the VFS inode interfaces. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/vfs_inode.c | 1371 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1371 insertions(+) create mode 100644 fs/9p/vfs_inode.c diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c new file mode 100644 index 0000000000000..ef78af7ef04ba --- /dev/null +++ b/fs/9p/vfs_inode.c @@ -0,0 +1,1371 @@ +/* + * linux/fs/9p/vfs_inode.c + * + * This file contians vfs inode ops for the 9P2000 protocol. + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/pagemap.h> +#include <linux/stat.h> +#include <linux/string.h> +#include <linux/smp_lock.h> +#include <linux/inet.h> +#include <linux/namei.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "9p.h" +#include "v9fs_vfs.h" +#include "conv.h" +#include "fid.h" + +static struct inode_operations v9fs_dir_inode_operations; +static struct inode_operations v9fs_file_inode_operations; +static struct inode_operations v9fs_symlink_inode_operations; + +/** + * unixmode2p9mode - convert unix mode bits to plan 9 + * @v9ses: v9fs session information + * @mode: mode to convert + * + */ + +static inline int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) +{ + int res; + res = mode & 0777; + if (S_ISDIR(mode)) + res |= V9FS_DMDIR; + if (v9ses->extended) { + if (S_ISLNK(mode)) + res |= V9FS_DMSYMLINK; + if (v9ses->nodev == 0) { + if (S_ISSOCK(mode)) + res |= V9FS_DMSOCKET; + if (S_ISFIFO(mode)) + res |= V9FS_DMNAMEDPIPE; + if (S_ISBLK(mode)) + res |= V9FS_DMDEVICE; + if (S_ISCHR(mode)) + res |= V9FS_DMDEVICE; + } + + if ((mode & S_ISUID) == S_ISUID) + res |= V9FS_DMSETUID; + if ((mode & S_ISGID) == S_ISGID) + res |= V9FS_DMSETGID; + if ((mode & V9FS_DMLINK)) + res |= V9FS_DMLINK; + } + + return res; +} + +/** + * p9mode2unixmode- convert plan9 mode bits to unix mode bits + * @v9ses: v9fs session information + * @mode: mode to convert + * + */ + +static inline int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) +{ + int res; + + res = mode & 0777; + + if ((mode & V9FS_DMDIR) == V9FS_DMDIR) + res |= S_IFDIR; + else if ((mode & V9FS_DMSYMLINK) && (v9ses->extended)) + res |= S_IFLNK; + else if ((mode & V9FS_DMSOCKET) && (v9ses->extended) + && (v9ses->nodev == 0)) + res |= S_IFSOCK; + else if ((mode & V9FS_DMNAMEDPIPE) && (v9ses->extended) + && (v9ses->nodev == 0)) + res |= S_IFIFO; + else if ((mode & V9FS_DMDEVICE) && (v9ses->extended) + && (v9ses->nodev == 0)) + res |= S_IFBLK; + else + res |= S_IFREG; + + if (v9ses->extended) { + if ((mode & V9FS_DMSETUID) == V9FS_DMSETUID) + res |= S_ISUID; + + if ((mode & V9FS_DMSETGID) == V9FS_DMSETGID) + res |= S_ISGID; + } + + return res; +} + +/** + * v9fs_blank_mistat - helper function to setup a 9P stat structure + * @v9ses: 9P session info (for determining extended mode) + * @mistat: structure to initialize + * + */ + +static inline void +v9fs_blank_mistat(struct v9fs_session_info *v9ses, struct v9fs_stat *mistat) +{ + mistat->type = ~0; + mistat->dev = ~0; + mistat->qid.type = ~0; + mistat->qid.version = ~0; + *((long long *)&mistat->qid.path) = ~0; + mistat->mode = ~0; + mistat->atime = ~0; + mistat->mtime = ~0; + mistat->length = ~0; + mistat->name = mistat->data; + mistat->uid = mistat->data; + mistat->gid = mistat->data; + mistat->muid = mistat->data; + if (v9ses->extended) { + mistat->n_uid = ~0; + mistat->n_gid = ~0; + mistat->n_muid = ~0; + mistat->extension = mistat->data; + } + *mistat->data = 0; +} + +/** + * v9fs_mistat2unix - convert mistat to unix stat + * @mistat: Plan 9 metadata (mistat) structure + * @stat: unix metadata (stat) structure to populate + * @sb: superblock + * + */ + +static void +v9fs_mistat2unix(struct v9fs_stat *mistat, struct stat *buf, + struct super_block *sb) +{ + struct v9fs_session_info *v9ses = sb ? sb->s_fs_info : NULL; + + buf->st_nlink = 1; + + buf->st_atime = mistat->atime; + buf->st_mtime = mistat->mtime; + buf->st_ctime = mistat->mtime; + + if (v9ses && v9ses->extended) { + /* TODO: string to uid mapping via user-space daemon */ + buf->st_uid = mistat->n_uid; + buf->st_gid = mistat->n_gid; + + sscanf(mistat->uid, "%x", (unsigned int *)&buf->st_uid); + sscanf(mistat->gid, "%x", (unsigned int *)&buf->st_gid); + } else { + buf->st_uid = v9ses->uid; + buf->st_gid = v9ses->gid; + } + + buf->st_uid = (unsigned short)-1; + buf->st_gid = (unsigned short)-1; + + if (v9ses && v9ses->extended) { + if (mistat->n_uid != -1) + sscanf(mistat->uid, "%x", (unsigned int *)&buf->st_uid); + + if (mistat->n_gid != -1) + sscanf(mistat->gid, "%x", (unsigned int *)&buf->st_gid); + } + + if (buf->st_uid == (unsigned short)-1) + buf->st_uid = v9ses->uid; + if (buf->st_gid == (unsigned short)-1) + buf->st_gid = v9ses->gid; + + buf->st_mode = p9mode2unixmode(v9ses, mistat->mode); + if ((S_ISBLK(buf->st_mode)) || (S_ISCHR(buf->st_mode))) { + char type = 0; + int major = -1; + int minor = -1; + sscanf(mistat->extension, "%c %u %u", &type, &major, &minor); + switch (type) { + case 'c': + buf->st_mode &= ~S_IFBLK; + buf->st_mode |= S_IFCHR; + break; + case 'b': + break; + default: + dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n", + type, mistat->extension); + }; + buf->st_rdev = MKDEV(major, minor); + } else + buf->st_rdev = 0; + + buf->st_size = mistat->length; + + buf->st_blksize = sb->s_blocksize; + buf->st_blocks = + (buf->st_size + buf->st_blksize - 1) >> sb->s_blocksize_bits; +} + +/** + * v9fs_get_inode - helper function to setup an inode + * @sb: superblock + * @mode: mode to setup inode with + * + */ + +struct inode *v9fs_get_inode(struct super_block *sb, int mode) +{ + struct inode *inode = NULL; + + dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); + + inode = new_inode(sb); + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = sb->s_blocksize; + inode->i_blocks = 0; + inode->i_rdev = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + + switch (mode & S_IFMT) { + case S_IFIFO: + case S_IFBLK: + case S_IFCHR: + case S_IFSOCK: + case S_IFREG: + inode->i_op = &v9fs_file_inode_operations; + inode->i_fop = &v9fs_file_operations; + break; + case S_IFDIR: + inode->i_nlink++; + inode->i_op = &v9fs_dir_inode_operations; + inode->i_fop = &v9fs_dir_operations; + break; + case S_IFLNK: + inode->i_op = &v9fs_symlink_inode_operations; + break; + default: + dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", + mode, mode & S_IFMT); + return ERR_PTR(-EINVAL); + } + } else { + eprintk(KERN_WARNING, "Problem allocating inode\n"); + return ERR_PTR(-ENOMEM); + } + return inode; +} + +/** + * v9fs_create - helper function to create files and directories + * @dir: directory inode file is being created in + * @file_dentry: dentry file is being created in + * @perm: permissions file is being created with + * @open_mode: resulting open mode for file ??? + * + */ + +static int +v9fs_create(struct inode *dir, + struct dentry *file_dentry, + unsigned int perm, unsigned int open_mode) +{ + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); + struct super_block *sb = dir->i_sb; + struct v9fs_fid *dirfid = + v9fs_fid_lookup(file_dentry->d_parent, FID_WALK); + struct v9fs_fid *fid = NULL; + struct inode *file_inode = NULL; + struct v9fs_fcall *fcall = NULL; + struct v9fs_qid qid; + struct stat newstat; + int dirfidnum = -1; + long newfid = -1; + int result = 0; + unsigned int iounit = 0; + + perm = unixmode2p9mode(v9ses, perm); + + dprintk(DEBUG_VFS, "dir: %p dentry: %p perm: %o mode: %o\n", dir, + file_dentry, perm, open_mode); + + if (!dirfid) + return -EBADF; + + dirfidnum = dirfid->fid; + if (dirfidnum < 0) { + dprintk(DEBUG_ERROR, "No fid for the directory #%lu\n", + dir->i_ino); + return -EBADF; + } + + if (file_dentry->d_inode) { + dprintk(DEBUG_ERROR, + "Odd. There is an inode for dir %lu, name :%s:\n", + dir->i_ino, file_dentry->d_name.name); + return -EEXIST; + } + + newfid = v9fs_get_idpool(&v9ses->fidpool); + if (newfid < 0) { + eprintk(KERN_WARNING, "no free fids available\n"); + return -ENOSPC; + } + + result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall); + if (result < 0) { + dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); + v9fs_put_idpool(newfid, &v9ses->fidpool); + newfid = 0; + goto CleanUpFid; + } + + kfree(fcall); + + result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name, + perm, open_mode, &fcall); + if (result < 0) { + dprintk(DEBUG_ERROR, "create fails: %s(%d)\n", + FCALL_ERROR(fcall), result); + + goto CleanUpFid; + } + + iounit = fcall->params.rcreate.iounit; + qid = fcall->params.rcreate.qid; + kfree(fcall); + + fid = v9fs_fid_create(file_dentry); + if (!fid) { + result = -ENOMEM; + goto CleanUpFid; + } + + fid->fid = newfid; + fid->fidopen = 0; + fid->fidcreate = 1; + fid->qid = qid; + fid->iounit = iounit; + fid->rdir_pos = 0; + fid->rdir_fcall = NULL; + fid->v9ses = v9ses; + + if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) || + (perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) || + (perm & V9FS_DMDEVICE)) + return 0; + + result = v9fs_t_stat(v9ses, newfid, &fcall); + if (result < 0) { + dprintk(DEBUG_ERROR, "stat error: %s(%d)\n", FCALL_ERROR(fcall), + result); + goto CleanUpFid; + } + + v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb); + + file_inode = v9fs_get_inode(sb, newstat.st_mode); + if ((!file_inode) || IS_ERR(file_inode)) { + dprintk(DEBUG_ERROR, "create inode failed\n"); + result = -EBADF; + goto CleanUpFid; + } + + v9fs_mistat2inode(fcall->params.rstat.stat, file_inode, sb); + kfree(fcall); + d_instantiate(file_dentry, file_inode); + + if (perm & V9FS_DMDIR) { + if (v9fs_t_clunk(v9ses, newfid, &fcall)) + dprintk(DEBUG_ERROR, "clunk for mkdir failed: %s\n", + FCALL_ERROR(fcall)); + + v9fs_put_idpool(newfid, &v9ses->fidpool); + kfree(fcall); + fid->fidopen = 0; + fid->fidcreate = 0; + d_drop(file_dentry); + } + + return 0; + + CleanUpFid: + kfree(fcall); + + if (newfid) { + if (v9fs_t_clunk(v9ses, newfid, &fcall)) + dprintk(DEBUG_ERROR, "clunk failed: %s\n", + FCALL_ERROR(fcall)); + + v9fs_put_idpool(newfid, &v9ses->fidpool); + kfree(fcall); + } + return result; +} + +/** + * v9fs_remove - helper function to remove files and directories + * @inode: directory inode that is being deleted + * @dentry: dentry that is being deleted + * @rmdir: where we are a file or a directory + * + */ + +static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) +{ + struct v9fs_fcall *fcall = NULL; + struct super_block *sb = NULL; + struct v9fs_session_info *v9ses = NULL; + struct v9fs_fid *v9fid = NULL; + struct inode *file_inode = NULL; + int fid = -1; + int result = 0; + + dprintk(DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, + rmdir); + + file_inode = file->d_inode; + sb = file_inode->i_sb; + v9ses = v9fs_inode2v9ses(file_inode); + v9fid = v9fs_fid_lookup(file, FID_OP); + + if (!v9fid) { + dprintk(DEBUG_ERROR, + "no v9fs_fid\n"); + return -EBADF; + } + + fid = v9fid->fid; + if (fid < 0) { + dprintk(DEBUG_ERROR, "inode #%lu, no fid!\n", + file_inode->i_ino); + return -EBADF; + } + + result = v9fs_t_remove(v9ses, fid, &fcall); + if (result < 0) + dprintk(DEBUG_ERROR, "remove of file fails: %s(%d)\n", + FCALL_ERROR(fcall), result); + else { + v9fs_put_idpool(fid, &v9ses->fidpool); + v9fs_fid_destroy(v9fid); + } + + kfree(fcall); + return result; +} + +/** + * v9fs_vfs_create - VFS hook to create files + * @inode: directory inode that is being deleted + * @dentry: dentry that is being deleted + * @perm: create permissions + * @nd: path information + * + */ + +static int +v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm, + struct nameidata *nd) +{ + return v9fs_create(inode, dentry, perm, O_RDWR); +} + +/** + * v9fs_vfs_mkdir - VFS mkdir hook to create a directory + * @i: inode that is being unlinked + * @dentry: dentry that is being unlinked + * @mode: mode for new directory + * + */ + +static int v9fs_vfs_mkdir(struct inode *inode, struct dentry *dentry, int mode) +{ + return v9fs_create(inode, dentry, mode | S_IFDIR, O_RDONLY); +} + +/** + * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode + * @dir: inode that is being walked from + * @dentry: dentry that is being walked to? + * @nameidata: path data + * + */ + +static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nameidata) +{ + struct super_block *sb; + struct v9fs_session_info *v9ses; + struct v9fs_fid *dirfid; + struct v9fs_fid *fid; + struct inode *inode; + struct v9fs_fcall *fcall = NULL; + struct stat newstat; + int dirfidnum = -1; + int newfid = -1; + int result = 0; + + dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", + dir, dentry->d_iname, dentry, nameidata); + + sb = dir->i_sb; + v9ses = v9fs_inode2v9ses(dir); + dirfid = v9fs_fid_lookup(dentry->d_parent, FID_WALK); + + if (!dirfid) { + dprintk(DEBUG_ERROR, "no dirfid\n"); + return ERR_PTR(-EINVAL); + } + + dirfidnum = dirfid->fid; + + if (dirfidnum < 0) { + dprintk(DEBUG_ERROR, "no dirfid for inode %p, #%lu\n", + dir, dir->i_ino); + return ERR_PTR(-EBADF); + } + + newfid = v9fs_get_idpool(&v9ses->fidpool); + if (newfid < 0) { + eprintk(KERN_WARNING, "newfid fails!\n"); + return ERR_PTR(-ENOSPC); + } + + result = + v9fs_t_walk(v9ses, dirfidnum, newfid, (char *)dentry->d_name.name, + NULL); + if (result < 0) { + v9fs_put_idpool(newfid, &v9ses->fidpool); + if (result == -ENOENT) { + d_add(dentry, NULL); + dprintk(DEBUG_ERROR, + "Return negative dentry %p count %d\n", + dentry, atomic_read(&dentry->d_count)); + return NULL; + } + dprintk(DEBUG_ERROR, "walk error:%d\n", result); + goto FreeFcall; + } + + result = v9fs_t_stat(v9ses, newfid, &fcall); + if (result < 0) { + dprintk(DEBUG_ERROR, "stat error\n"); + goto FreeFcall; + } + + v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb); + inode = v9fs_get_inode(sb, newstat.st_mode); + + if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { + eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", + PTR_ERR(inode)); + + result = -ENOSPC; + goto FreeFcall; + } + + inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid); + + fid = v9fs_fid_create(dentry); + if (fid == NULL) { + dprintk(DEBUG_ERROR, "couldn't insert\n"); + result = -ENOMEM; + goto FreeFcall; + } + + fid->fid = newfid; + fid->fidopen = 0; + fid->v9ses = v9ses; + fid->qid = fcall->params.rstat.stat->qid; + + dentry->d_op = &v9fs_dentry_operations; + v9fs_mistat2inode(fcall->params.rstat.stat, inode, inode->i_sb); + + d_add(dentry, inode); + kfree(fcall); + + return NULL; + + FreeFcall: + kfree(fcall); + return ERR_PTR(result); +} + +/** + * v9fs_vfs_unlink - VFS unlink hook to delete an inode + * @i: inode that is being unlinked + * @dentry: dentry that is being unlinked + * + */ + +static int v9fs_vfs_unlink(struct inode *i, struct dentry *d) +{ + return v9fs_remove(i, d, 0); +} + +/** + * v9fs_vfs_rmdir - VFS unlink hook to delete a directory + * @i: inode that is being unlinked + * @dentry: dentry that is being unlinked + * + */ + +static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) +{ + return v9fs_remove(i, d, 1); +} + +/** + * v9fs_vfs_rename - VFS hook to rename an inode + * @old_dir: old dir inode + * @old_dentry: old dentry + * @new_dir: new dir inode + * @new_dentry: new dentry + * + */ + +static int +v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct inode *old_inode = old_dentry->d_inode; + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); + struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry, FID_WALK); + struct v9fs_fid *olddirfid = + v9fs_fid_lookup(old_dentry->d_parent, FID_WALK); + struct v9fs_fid *newdirfid = + v9fs_fid_lookup(new_dentry->d_parent, FID_WALK); + struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); + struct v9fs_fcall *fcall = NULL; + int fid = -1; + int olddirfidnum = -1; + int newdirfidnum = -1; + int retval = 0; + + dprintk(DEBUG_VFS, "\n"); + + if ((!oldfid) || (!olddirfid) || (!newdirfid)) { + dprintk(DEBUG_ERROR, "problem with arguments\n"); + return -EBADF; + } + + /* 9P can only handle file rename in the same directory */ + if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { + dprintk(DEBUG_ERROR, "old dir and new dir are different\n"); + retval = -EPERM; + goto FreeFcallnBail; + } + + fid = oldfid->fid; + olddirfidnum = olddirfid->fid; + newdirfidnum = newdirfid->fid; + + if (fid < 0) { + dprintk(DEBUG_ERROR, "no fid for old file #%lu\n", + old_inode->i_ino); + retval = -EBADF; + goto FreeFcallnBail; + } + + v9fs_blank_mistat(v9ses, mistat); + + strcpy(mistat->data + 1, v9ses->name); + mistat->name = mistat->data + 1 + strlen(v9ses->name); + + if (new_dentry->d_name.len > + (v9ses->maxdata - strlen(v9ses->name) - sizeof(struct v9fs_stat))) { + dprintk(DEBUG_ERROR, "new name too long\n"); + goto FreeFcallnBail; + } + + strcpy(mistat->name, new_dentry->d_name.name); + retval = v9fs_t_wstat(v9ses, fid, mistat, &fcall); + + FreeFcallnBail: + kfree(mistat); + + if (retval < 0) + dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", + FCALL_ERROR(fcall)); + + kfree(fcall); + return retval; +} + +/** + * v9fs_vfs_getattr - retreive file metadata + * @mnt - mount information + * @dentry - file to get attributes on + * @stat - metadata structure to populate + * + */ + +static int +v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct v9fs_fcall *fcall = NULL; + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); + struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP); + int err = -EPERM; + + dprintk(DEBUG_VFS, "dentry: %p\n", dentry); + if (!fid) { + dprintk(DEBUG_ERROR, + "couldn't find fid associated with dentry\n"); + return -EBADF; + } + + err = v9fs_t_stat(v9ses, fid->fid, &fcall); + + if (err < 0) + dprintk(DEBUG_ERROR, "stat error\n"); + else { + v9fs_mistat2inode(fcall->params.rstat.stat, dentry->d_inode, + dentry->d_inode->i_sb); + generic_fillattr(dentry->d_inode, stat); + } + + kfree(fcall); + return err; +} + +/** + * v9fs_vfs_setattr - set file metadata + * @dentry: file whose metadata to set + * @iattr: metadata assignment structure + * + */ + +static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) +{ + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); + struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP); + struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); + struct v9fs_fcall *fcall = NULL; + int res = -EPERM; + + dprintk(DEBUG_VFS, "\n"); + if (!fid) { + dprintk(DEBUG_ERROR, + "Couldn't find fid associated with dentry\n"); + return -EBADF; + } + + if (!mistat) + return -ENOMEM; + + v9fs_blank_mistat(v9ses, mistat); + if (iattr->ia_valid & ATTR_MODE) + mistat->mode = unixmode2p9mode(v9ses, iattr->ia_mode); + + if (iattr->ia_valid & ATTR_MTIME) + mistat->mtime = iattr->ia_mtime.tv_sec; + + if (iattr->ia_valid & ATTR_ATIME) + mistat->atime = iattr->ia_atime.tv_sec; + + if (iattr->ia_valid & ATTR_SIZE) + mistat->length = iattr->ia_size; + + if (v9ses->extended) { + char *uid = kmalloc(strlen(mistat->uid), GFP_KERNEL); + char *gid = kmalloc(strlen(mistat->gid), GFP_KERNEL); + char *muid = kmalloc(strlen(mistat->muid), GFP_KERNEL); + char *name = kmalloc(strlen(mistat->name), GFP_KERNEL); + char *extension = kmalloc(strlen(mistat->extension), + GFP_KERNEL); + + if ((!uid) || (!gid) || (!muid) || (!name) || (!extension)) { + kfree(uid); + kfree(gid); + kfree(muid); + kfree(name); + kfree(extension); + + return -ENOMEM; + } + + strcpy(uid, mistat->uid); + strcpy(gid, mistat->gid); + strcpy(muid, mistat->muid); + strcpy(name, mistat->name); + strcpy(extension, mistat->extension); + + if (iattr->ia_valid & ATTR_UID) { + if (strlen(uid) != 8) { + dprintk(DEBUG_ERROR, "uid strlen is %u not 8\n", + (unsigned int)strlen(uid)); + sprintf(uid, "%08x", iattr->ia_uid); + } else { + kfree(uid); + uid = kmalloc(9, GFP_KERNEL); + } + + sprintf(uid, "%08x", iattr->ia_uid); + mistat->n_uid = iattr->ia_uid; + } + + if (iattr->ia_valid & ATTR_GID) { + if (strlen(gid) != 8) + dprintk(DEBUG_ERROR, "gid strlen is %u not 8\n", + (unsigned int)strlen(gid)); + else { + kfree(gid); + gid = kmalloc(9, GFP_KERNEL); + } + + sprintf(gid, "%08x", iattr->ia_gid); + mistat->n_gid = iattr->ia_gid; + } + + mistat->uid = mistat->data; + strcpy(mistat->uid, uid); + mistat->gid = mistat->data + strlen(uid) + 1; + strcpy(mistat->gid, gid); + mistat->muid = mistat->gid + strlen(gid) + 1; + strcpy(mistat->muid, muid); + mistat->name = mistat->muid + strlen(muid) + 1; + strcpy(mistat->name, name); + mistat->extension = mistat->name + strlen(name) + 1; + strcpy(mistat->extension, extension); + + kfree(uid); + kfree(gid); + kfree(muid); + kfree(name); + kfree(extension); + } + + res = v9fs_t_wstat(v9ses, fid->fid, mistat, &fcall); + + if (res < 0) + dprintk(DEBUG_ERROR, "wstat error: %s\n", FCALL_ERROR(fcall)); + + kfree(mistat); + kfree(fcall); + + if (res >= 0) + res = inode_setattr(dentry->d_inode, iattr); + + return res; +} + +/** + * v9fs_mistat2inode - populate an inode structure with mistat info + * @mistat: Plan 9 metadata (mistat) structure + * @inode: inode to populate + * @sb: superblock of filesystem + * + */ + +void +v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode, + struct super_block *sb) +{ + struct v9fs_session_info *v9ses = sb->s_fs_info; + + inode->i_nlink = 1; + + inode->i_atime.tv_sec = mistat->atime; + inode->i_mtime.tv_sec = mistat->mtime; + inode->i_ctime.tv_sec = mistat->mtime; + + inode->i_uid = -1; + inode->i_gid = -1; + + if (v9ses->extended) { + /* TODO: string to uid mapping via user-space daemon */ + inode->i_uid = mistat->n_uid; + inode->i_gid = mistat->n_gid; + + if (mistat->n_uid == -1) + sscanf(mistat->uid, "%x", &inode->i_uid); + + if (mistat->n_gid == -1) + sscanf(mistat->gid, "%x", &inode->i_gid); + } + + if (inode->i_uid == -1) + inode->i_uid = v9ses->uid; + if (inode->i_gid == -1) + inode->i_gid = v9ses->gid; + + inode->i_mode = p9mode2unixmode(v9ses, mistat->mode); + if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { + char type = 0; + int major = -1; + int minor = -1; + sscanf(mistat->extension, "%c %u %u", &type, &major, &minor); + switch (type) { + case 'c': + inode->i_mode &= ~S_IFBLK; + inode->i_mode |= S_IFCHR; + break; + case 'b': + break; + default: + dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n", + type, mistat->extension); + }; + inode->i_rdev = MKDEV(major, minor); + } else + inode->i_rdev = 0; + + inode->i_size = mistat->length; + + inode->i_blksize = sb->s_blocksize; + inode->i_blocks = + (inode->i_size + inode->i_blksize - 1) >> sb->s_blocksize_bits; +} + +/** + * v9fs_qid2ino - convert qid into inode number + * @qid: qid to hash + * + * BUG: potential for inode number collisions? + */ + +ino_t v9fs_qid2ino(struct v9fs_qid *qid) +{ + u64 path = qid->path + 2; + ino_t i = 0; + + if (sizeof(ino_t) == sizeof(path)) + memcpy(&i, &path, sizeof(ino_t)); + else + i = (ino_t) (path ^ (path >> 32)); + + return i; +} + +/** + * v9fs_vfs_symlink - helper function to create symlinks + * @dir: directory inode containing symlink + * @dentry: dentry for symlink + * @symname: symlink data + * + * See 9P2000.u RFC for more information + * + */ + +static int +v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +{ + int retval = -EPERM; + struct v9fs_fid *newfid; + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); + struct super_block *sb = dir ? dir->i_sb : NULL; + struct v9fs_fcall *fcall = NULL; + struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); + + dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, + symname); + + if ((!dentry) || (!sb) || (!v9ses)) { + dprintk(DEBUG_ERROR, "problem with arguments\n"); + return -EBADF; + } + + if (!v9ses->extended) { + dprintk(DEBUG_ERROR, "not extended\n"); + goto FreeFcall; + } + + /* issue a create */ + retval = v9fs_create(dir, dentry, S_IFLNK, 0); + if (retval != 0) + goto FreeFcall; + + newfid = v9fs_fid_lookup(dentry, FID_OP); + + /* issue a twstat */ + v9fs_blank_mistat(v9ses, mistat); + strcpy(mistat->data + 1, symname); + mistat->extension = mistat->data + 1; + retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); + if (retval < 0) { + dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", + FCALL_ERROR(fcall)); + goto FreeFcall; + } + + kfree(fcall); + + if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) { + dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n", + FCALL_ERROR(fcall)); + goto FreeFcall; + } + + d_drop(dentry); /* FID - will this also clunk? */ + + FreeFcall: + kfree(mistat); + kfree(fcall); + + return retval; +} + +/** + * v9fs_readlink - read a symlink's location (internal version) + * @dentry: dentry for symlink + * @buf: buffer to load symlink location into + * @buflen: length of buffer + * + */ + +static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + int retval = -EPERM; + + struct v9fs_fcall *fcall = NULL; + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); + struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP); + + if (!fid) { + dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n"); + retval = -EBADF; + goto FreeFcall; + } + + if (!v9ses->extended) { + retval = -EBADF; + dprintk(DEBUG_ERROR, "not extended\n"); + goto FreeFcall; + } + + dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name); + retval = v9fs_t_stat(v9ses, fid->fid, &fcall); + + if (retval < 0) { + dprintk(DEBUG_ERROR, "stat error\n"); + goto FreeFcall; + } + + if (!fcall) + return -EIO; + + if (!(fcall->params.rstat.stat->mode & V9FS_DMSYMLINK)) { + retval = -EINVAL; + goto FreeFcall; + } + + /* copy extension buffer into buffer */ + if (strlen(fcall->params.rstat.stat->extension) < buflen) + buflen = strlen(fcall->params.rstat.stat->extension); + + memcpy(buffer, fcall->params.rstat.stat->extension, buflen + 1); + + retval = buflen; + + FreeFcall: + kfree(fcall); + + return retval; +} + +/** + * v9fs_vfs_readlink - read a symlink's location + * @dentry: dentry for symlink + * @buf: buffer to load symlink location into + * @buflen: length of buffer + * + */ + +static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, + int buflen) +{ + int retval; + int ret; + char *link = __getname(); + + if (strlen(link) < buflen) + buflen = strlen(link); + + dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); + + retval = v9fs_readlink(dentry, link, buflen); + + if (retval > 0) { + if ((ret = copy_to_user(buffer, link, retval)) != 0) { + dprintk(DEBUG_ERROR, "problem copying to user: %d\n", + ret); + retval = ret; + } + } + + putname(link); + return retval; +} + +/** + * v9fs_vfs_follow_link - follow a symlink path + * @dentry: dentry for symlink + * @nd: nameidata + * + */ + +static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + int len = 0; + char *link = __getname(); + + dprintk(DEBUG_VFS, "%s n", dentry->d_name.name); + + if (!link) + link = ERR_PTR(-ENOMEM); + else { + len = v9fs_readlink(dentry, link, strlen(link)); + + if (len < 0) { + putname(link); + link = ERR_PTR(len); + } else + link[len] = 0; + } + nd_set_link(nd, link); + + return NULL; +} + +/** + * v9fs_vfs_put_link - release a symlink path + * @dentry: dentry for symlink + * @nd: nameidata + * + */ + +static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) +{ + char *s = nd_get_link(nd); + + dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); + if (!IS_ERR(s)) + putname(s); +} + +/** + * v9fs_vfs_link - create a hardlink + * @old_dentry: dentry for file to link to + * @dir: inode destination for new link + * @new_dentry: dentry for link + * + */ + +/* XXX - lots of code dup'd from symlink and creates, + * figure out a better reuse strategy + */ + +static int +v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) +{ + int retval = -EPERM; + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); + struct v9fs_fcall *fcall = NULL; + struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); + struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry, FID_OP); + struct v9fs_fid *newfid = NULL; + char *symname = __getname(); + + dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, + old_dentry->d_name.name); + + if (!v9ses->extended) { + dprintk(DEBUG_ERROR, "not extended\n"); + goto FreeMem; + } + + /* get fid of old_dentry */ + sprintf(symname, "hardlink(%d)\n", oldfid->fid); + + /* issue a create */ + retval = v9fs_create(dir, dentry, V9FS_DMLINK, 0); + if (retval != 0) + goto FreeMem; + + newfid = v9fs_fid_lookup(dentry, FID_OP); + if (!newfid) { + dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); + goto FreeMem; + } + + /* issue a twstat */ + v9fs_blank_mistat(v9ses, mistat); + strcpy(mistat->data + 1, symname); + mistat->extension = mistat->data + 1; + retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); + if (retval < 0) { + dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", + FCALL_ERROR(fcall)); + goto FreeMem; + } + + kfree(fcall); + + if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) { + dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n", + FCALL_ERROR(fcall)); + goto FreeMem; + } + + d_drop(dentry); /* FID - will this also clunk? */ + + kfree(fcall); + fcall = NULL; + + FreeMem: + kfree(mistat); + kfree(fcall); + putname(symname); + return retval; +} + +/** + * v9fs_vfs_mknod - create a special file + * @dir: inode destination for new link + * @dentry: dentry for file + * @mode: mode for creation + * @dev_t: device associated with special file + * + */ + +static int +v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) +{ + int retval = -EPERM; + struct v9fs_fid *newfid; + struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); + struct v9fs_fcall *fcall = NULL; + struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); + char *symname = __getname(); + + dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, + dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); + + if (!new_valid_dev(rdev)) { + retval = -EINVAL; + goto FreeMem; + } + + if (!v9ses->extended) { + dprintk(DEBUG_ERROR, "not extended\n"); + goto FreeMem; + } + + /* issue a create */ + retval = v9fs_create(dir, dentry, mode, 0); + + if (retval != 0) + goto FreeMem; + + newfid = v9fs_fid_lookup(dentry, FID_OP); + if (!newfid) { + dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n"); + retval = -EINVAL; + goto FreeMem; + } + + /* build extension */ + if (S_ISBLK(mode)) + sprintf(symname, "b %u %u", MAJOR(rdev), MINOR(rdev)); + else if (S_ISCHR(mode)) + sprintf(symname, "c %u %u", MAJOR(rdev), MINOR(rdev)); + else if (S_ISFIFO(mode)) ; /* DO NOTHING */ + else { + retval = -EINVAL; + goto FreeMem; + } + + if (!S_ISFIFO(mode)) { + /* issue a twstat */ + v9fs_blank_mistat(v9ses, mistat); + strcpy(mistat->data + 1, symname); + mistat->extension = mistat->data + 1; + retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); + if (retval < 0) { + dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", + FCALL_ERROR(fcall)); + goto FreeMem; + } + + kfree(fcall); + } + + /* need to update dcache so we show up */ + kfree(fcall); + + if (v9fs_t_clunk(v9ses, newfid->fid, &fcall)) { + dprintk(DEBUG_ERROR, "clunk for symlink failed: %s\n", + FCALL_ERROR(fcall)); + goto FreeMem; + } + + d_drop(dentry); /* FID - will this also clunk? */ + + FreeMem: + kfree(mistat); + kfree(fcall); + putname(symname); + + return retval; +} + +static struct inode_operations v9fs_dir_inode_operations = { + .create = v9fs_vfs_create, + .lookup = v9fs_vfs_lookup, + .symlink = v9fs_vfs_symlink, + .link = v9fs_vfs_link, + .unlink = v9fs_vfs_unlink, + .mkdir = v9fs_vfs_mkdir, + .rmdir = v9fs_vfs_rmdir, + .mknod = v9fs_vfs_mknod, + .rename = v9fs_vfs_rename, + .readlink = v9fs_vfs_readlink, + .getattr = v9fs_vfs_getattr, + .setattr = v9fs_vfs_setattr, +}; + +static struct inode_operations v9fs_file_inode_operations = { + .getattr = v9fs_vfs_getattr, + .setattr = v9fs_vfs_setattr, +}; + +static struct inode_operations v9fs_symlink_inode_operations = { + .readlink = v9fs_vfs_readlink, + .follow_link = v9fs_vfs_follow_link, + .put_link = v9fs_vfs_put_link, + .getattr = v9fs_vfs_getattr, + .setattr = v9fs_vfs_setattr, +}; -- GitLab From 9e82cf6a802a72f0f447eb4c76d6a3fc8736a31d Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:20 -0700 Subject: [PATCH 210/563] [PATCH] v9fs: VFS superblock operations and glue This part of the patch contains VFS superblock and mapping code. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/v9fs.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++ fs/9p/v9fs.h | 105 +++++++++++ fs/9p/v9fs_vfs.h | 53 ++++++ fs/9p/vfs_super.c | 271 ++++++++++++++++++++++++++++ 4 files changed, 877 insertions(+) create mode 100644 fs/9p/v9fs.c create mode 100644 fs/9p/v9fs.h create mode 100644 fs/9p/v9fs_vfs.h create mode 100644 fs/9p/vfs_super.c diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c new file mode 100644 index 0000000000000..14d663ebfcbcc --- /dev/null +++ b/fs/9p/v9fs.c @@ -0,0 +1,448 @@ +/* + * linux/fs/9p/v9fs.c + * + * This file contains functions assisting in mapping VFS to 9P2000 + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/parser.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "9p.h" +#include "v9fs_vfs.h" +#include "transport.h" +#include "mux.h" +#include "conv.h" + +/* TODO: sysfs or debugfs interface */ +int v9fs_debug_level = 0; /* feature-rific global debug level */ + +/* + * Option Parsing (code inspired by NFS code) + * + */ + +enum { + /* Options that take integer arguments */ + Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, Opt_debug, + Opt_rfdno, Opt_wfdno, + /* String options */ + Opt_name, Opt_remotename, + /* Options that take no arguments */ + Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, + /* Error token */ + Opt_err +}; + +static match_table_t tokens = { + {Opt_port, "port=%u"}, + {Opt_msize, "msize=%u"}, + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_afid, "afid=%u"}, + {Opt_rfdno, "rfdno=%u"}, + {Opt_wfdno, "wfdno=%u"}, + {Opt_debug, "debug=%u"}, + {Opt_name, "name=%s"}, + {Opt_remotename, "aname=%s"}, + {Opt_unix, "proto=unix"}, + {Opt_tcp, "proto=tcp"}, + {Opt_fd, "proto=fd"}, + {Opt_tcp, "tcp"}, + {Opt_unix, "unix"}, + {Opt_fd, "fd"}, + {Opt_legacy, "noextend"}, + {Opt_nodevmap, "nodevmap"}, + {Opt_err, NULL} +}; + +/* + * Parse option string. + */ + +/** + * v9fs_parse_options - parse mount options into session structure + * @options: options string passed from mount + * @v9ses: existing v9fs session information + * + */ + +static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + int option; + int ret; + + /* setup defaults */ + v9ses->port = V9FS_PORT; + v9ses->maxdata = 9000; + v9ses->proto = PROTO_TCP; + v9ses->extended = 1; + v9ses->afid = ~0; + v9ses->debug = 0; + v9ses->rfdno = ~0; + v9ses->wfdno = ~0; + + if (!options) + return; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + token = match_token(p, tokens, args); + if (token < Opt_name) { + if ((ret = match_int(&args[0], &option)) < 0) { + dprintk(DEBUG_ERROR, + "integer field, but no integer?\n"); + continue; + } + + } + switch (token) { + case Opt_port: + v9ses->port = option; + break; + case Opt_msize: + v9ses->maxdata = option; + break; + case Opt_uid: + v9ses->uid = option; + break; + case Opt_gid: + v9ses->gid = option; + break; + case Opt_afid: + v9ses->afid = option; + break; + case Opt_rfdno: + v9ses->rfdno = option; + break; + case Opt_wfdno: + v9ses->wfdno = option; + break; + case Opt_debug: + v9ses->debug = option; + break; + case Opt_tcp: + v9ses->proto = PROTO_TCP; + break; + case Opt_unix: + v9ses->proto = PROTO_UNIX; + break; + case Opt_fd: + v9ses->proto = PROTO_FD; + break; + case Opt_name: + match_strcpy(v9ses->name, &args[0]); + break; + case Opt_remotename: + match_strcpy(v9ses->remotename, &args[0]); + break; + case Opt_legacy: + v9ses->extended = 0; + break; + case Opt_nodevmap: + v9ses->nodev = 1; + break; + default: + continue; + } + } +} + +/** + * v9fs_inode2v9ses - safely extract v9fs session info from super block + * @inode: inode to extract information from + * + * Paranoid function to extract v9ses information from superblock, + * if anything is missing it will report an error. + * + */ + +struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode) +{ + return (inode->i_sb->s_fs_info); +} + +/** + * v9fs_get_idpool - allocate numeric id from pool + * @p - pool to allocate from + * + * XXX - This seems to be an awful generic function, should it be in idr.c with + * the lock included in struct idr? + */ + +int v9fs_get_idpool(struct v9fs_idpool *p) +{ + int i = 0; + int error; + +retry: + if (idr_pre_get(&p->pool, GFP_KERNEL) == 0) + return 0; + + if (down_interruptible(&p->lock) == -EINTR) { + eprintk(KERN_WARNING, "Interrupted while locking\n"); + return -1; + } + + error = idr_get_new(&p->pool, NULL, &i); + up(&p->lock); + + if (error == -EAGAIN) + goto retry; + else if (error) + return -1; + + return i; +} + +/** + * v9fs_put_idpool - release numeric id from pool + * @p - pool to allocate from + * + * XXX - This seems to be an awful generic function, should it be in idr.c with + * the lock included in struct idr? + */ + +void v9fs_put_idpool(int id, struct v9fs_idpool *p) +{ + if (down_interruptible(&p->lock) == -EINTR) { + eprintk(KERN_WARNING, "Interrupted while locking\n"); + return; + } + idr_remove(&p->pool, id); + up(&p->lock); +} + +/** + * v9fs_session_init - initialize session + * @v9ses: session information structure + * @dev_name: device being mounted + * @data: options + * + */ + +int +v9fs_session_init(struct v9fs_session_info *v9ses, + const char *dev_name, char *data) +{ + struct v9fs_fcall *fcall = NULL; + struct v9fs_transport *trans_proto; + int n = 0; + int newfid = -1; + int retval = -EINVAL; + + v9ses->name = __getname(); + if (!v9ses->name) + return -ENOMEM; + + v9ses->remotename = __getname(); + if (!v9ses->remotename) { + putname(v9ses->name); + return -ENOMEM; + } + + strcpy(v9ses->name, V9FS_DEFUSER); + strcpy(v9ses->remotename, V9FS_DEFANAME); + + v9fs_parse_options(data, v9ses); + + /* set global debug level */ + v9fs_debug_level = v9ses->debug; + + /* id pools that are session-dependent: FIDs and TIDs */ + idr_init(&v9ses->fidpool.pool); + init_MUTEX(&v9ses->fidpool.lock); + idr_init(&v9ses->tidpool.pool); + init_MUTEX(&v9ses->tidpool.lock); + + + switch (v9ses->proto) { + case PROTO_TCP: + trans_proto = &v9fs_trans_tcp; + break; + case PROTO_UNIX: + trans_proto = &v9fs_trans_unix; + *v9ses->remotename = 0; + break; + case PROTO_FD: + trans_proto = &v9fs_trans_fd; + *v9ses->remotename = 0; + if((v9ses->wfdno == ~0) || (v9ses->rfdno == ~0)) { + printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); + retval = -ENOPROTOOPT; + goto SessCleanUp; + } + break; + default: + printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); + retval = -ENOPROTOOPT; + goto SessCleanUp; + }; + + v9ses->transport = trans_proto; + + if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) { + eprintk(KERN_ERR, "problem initializing transport\n"); + goto SessCleanUp; + } + + v9ses->inprogress = 0; + v9ses->shutdown = 0; + v9ses->session_hung = 0; + + if ((retval = v9fs_mux_init(v9ses, dev_name)) < 0) { + dprintk(DEBUG_ERROR, "problem initializing mux\n"); + goto SessCleanUp; + } + + if (v9ses->afid == ~0) { + if (v9ses->extended) + retval = + v9fs_t_version(v9ses, v9ses->maxdata, "9P2000.u", + &fcall); + else + retval = v9fs_t_version(v9ses, v9ses->maxdata, "9P2000", + &fcall); + + if (retval < 0) { + dprintk(DEBUG_ERROR, "v9fs_t_version failed\n"); + goto FreeFcall; + } + + /* Really should check for 9P1 and report error */ + if (!strcmp(fcall->params.rversion.version, "9P2000.u")) { + dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n"); + v9ses->extended = 1; + } else { + dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n"); + v9ses->extended = 0; + } + + n = fcall->params.rversion.msize; + kfree(fcall); + + if (n < v9ses->maxdata) + v9ses->maxdata = n; + } + + newfid = v9fs_get_idpool(&v9ses->fidpool); + if (newfid < 0) { + eprintk(KERN_WARNING, "couldn't allocate FID\n"); + retval = -ENOMEM; + goto SessCleanUp; + } + /* it is a little bit ugly, but we have to prevent newfid */ + /* being the same as afid, so if it is, get a new fid */ + if (v9ses->afid != ~0 && newfid == v9ses->afid) { + newfid = v9fs_get_idpool(&v9ses->fidpool); + if (newfid < 0) { + eprintk(KERN_WARNING, "couldn't allocate FID\n"); + retval = -ENOMEM; + goto SessCleanUp; + } + } + + if ((retval = + v9fs_t_attach(v9ses, v9ses->name, v9ses->remotename, newfid, + v9ses->afid, NULL)) + < 0) { + dprintk(DEBUG_ERROR, "cannot attach\n"); + goto SessCleanUp; + } + + if (v9ses->afid != ~0) { + if (v9fs_t_clunk(v9ses, v9ses->afid, NULL)) + dprintk(DEBUG_ERROR, "clunk failed\n"); + } + + return newfid; + + FreeFcall: + kfree(fcall); + + SessCleanUp: + v9fs_session_close(v9ses); + return retval; +} + +/** + * v9fs_session_close - shutdown a session + * @v9ses: session information structure + * + */ + +void v9fs_session_close(struct v9fs_session_info *v9ses) +{ + if (v9ses->recvproc) { + send_sig(SIGKILL, v9ses->recvproc, 1); + wait_for_completion(&v9ses->proccmpl); + } + + if (v9ses->transport) + v9ses->transport->close(v9ses->transport); + + putname(v9ses->name); + putname(v9ses->remotename); +} + +extern int v9fs_error_init(void); + +/** + * v9fs_init - Initialize module + * + */ + +static int __init init_v9fs(void) +{ + v9fs_error_init(); + + printk(KERN_INFO "Installing v9fs 9P2000 file system support\n"); + + return register_filesystem(&v9fs_fs_type); +} + +/** + * v9fs_init - shutdown module + * + */ + +static void __exit exit_v9fs(void) +{ + unregister_filesystem(&v9fs_fs_type); +} + +module_init(init_v9fs) +module_exit(exit_v9fs) + +MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); +MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>"); +MODULE_LICENSE("GPL"); diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h new file mode 100644 index 0000000000000..52203027b1586 --- /dev/null +++ b/fs/9p/v9fs.h @@ -0,0 +1,105 @@ +/* + * V9FS definitions. + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +/* + * Idpool structure provides lock and id management + * + */ + +struct v9fs_idpool { + struct semaphore lock; + struct idr pool; +}; + +/* + * Session structure provides information for an opened session + * + */ + +struct v9fs_session_info { + /* options */ + unsigned int maxdata; + unsigned char extended; /* set to 1 if we are using UNIX extensions */ + unsigned char nodev; /* set to 1 if no disable device mapping */ + unsigned short port; /* port to connect to */ + unsigned short debug; /* debug level */ + unsigned short proto; /* protocol to use */ + unsigned int afid; /* authentication fid */ + unsigned int rfdno; /* read file descriptor number */ + unsigned int wfdno; /* write file descriptor number */ + + + char *name; /* user name to mount as */ + char *remotename; /* name of remote hierarchy being mounted */ + unsigned int uid; /* default uid/muid for legacy support */ + unsigned int gid; /* default gid for legacy support */ + + /* book keeping */ + struct v9fs_idpool fidpool; /* The FID pool for file descriptors */ + struct v9fs_idpool tidpool; /* The TID pool for transactions ids */ + + /* transport information */ + struct v9fs_transport *transport; + + int inprogress; /* session in progress => true */ + int shutdown; /* session shutting down. no more attaches. */ + unsigned char session_hung; + + /* mux private data */ + struct v9fs_fcall *curfcall; + wait_queue_head_t read_wait; + struct completion fcread; + struct completion proccmpl; + struct task_struct *recvproc; + + spinlock_t muxlock; + struct list_head mux_fcalls; +}; + +/* possible values of ->proto */ +enum { + PROTO_TCP, + PROTO_UNIX, + PROTO_FD, +}; + +int v9fs_session_init(struct v9fs_session_info *, const char *, char *); +struct v9fs_session_info *v9fs_inode2v9ses(struct inode *); +void v9fs_session_close(struct v9fs_session_info *v9ses); +int v9fs_get_idpool(struct v9fs_idpool *p); +void v9fs_put_idpool(int id, struct v9fs_idpool *p); +int v9fs_get_option(char *opts, char *name, char *buf, int buflen); +long long v9fs_get_int_option(char *opts, char *name, long long dflt); +int v9fs_parse_tcp_devname(const char *devname, char **addr, char **remotename); + +#define V9FS_MAGIC 0x01021997 + +/* other default globals */ +#define V9FS_PORT 564 +#define V9FS_DEFUSER "nobody" +#define V9FS_DEFANAME "" + +/* inital pool sizes for fids and tags */ +#define V9FS_START_FIDS 8192 +#define V9FS_START_TIDS 256 diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h new file mode 100644 index 0000000000000..2f2cea7ee3e71 --- /dev/null +++ b/fs/9p/v9fs_vfs.h @@ -0,0 +1,53 @@ +/* + * V9FS VFS extensions. + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +/* plan9 semantics are that created files are implicitly opened. + * But linux semantics are that you call create, then open. + * the plan9 approach is superior as it provides an atomic + * open. + * we track the create fid here. When the file is opened, if fidopen is + * non-zero, we use the fid and can skip some steps. + * there may be a better way to do this, but I don't know it. + * one BAD way is to clunk the fid on create, then open it again: + * you lose the atomicity of file open + */ + +/* special case: + * unlink calls remove, which is an implicit clunk. So we have to track + * that kind of thing so that we don't try to clunk a dead fid. + */ + +extern struct file_system_type v9fs_fs_type; +extern struct file_operations v9fs_file_operations; +extern struct file_operations v9fs_dir_operations; +extern struct dentry_operations v9fs_dentry_operations; + +struct inode *v9fs_get_inode(struct super_block *sb, int mode); +ino_t v9fs_qid2ino(struct v9fs_qid *qid); +void v9fs_mistat2inode(struct v9fs_stat *, struct inode *, + struct super_block *); +int v9fs_dir_release(struct inode *inode, struct file *filp); +int v9fs_file_open(struct inode *inode, struct file *file); +void v9fs_inode2mistat(struct inode *inode, struct v9fs_stat *mistat); +void v9fs_dentry_release(struct dentry *); diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c new file mode 100644 index 0000000000000..ce0778acc90ab --- /dev/null +++ b/fs/9p/vfs_super.c @@ -0,0 +1,271 @@ +/* + * linux/fs/9p/vfs_super.c + * + * This file contians superblock ops for 9P2000. It is intended that + * you mount this file system on directories. + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/kernel.h> +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/stat.h> +#include <linux/string.h> +#include <linux/smp_lock.h> +#include <linux/inet.h> +#include <linux/pagemap.h> +#include <linux/seq_file.h> +#include <linux/mount.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "9p.h" +#include "v9fs_vfs.h" +#include "conv.h" +#include "fid.h" + +static void v9fs_clear_inode(struct inode *); +static struct super_operations v9fs_super_ops; + +/** + * v9fs_clear_inode - release an inode + * @inode: inode to release + * + */ + +static void v9fs_clear_inode(struct inode *inode) +{ + filemap_fdatawrite(inode->i_mapping); +} + +/** + * v9fs_set_super - set the superblock + * @s: super block + * @data: file system specific data + * + */ + +static int v9fs_set_super(struct super_block *s, void *data) +{ + s->s_fs_info = data; + return set_anon_super(s, data); +} + +/** + * v9fs_fill_super - populate superblock with info + * @sb: superblock + * @v9ses: session information + * + */ + +static void +v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, + int flags) +{ + sb->s_maxbytes = MAX_LFS_FILESIZE; + sb->s_blocksize_bits = fls(v9ses->maxdata - 1); + sb->s_blocksize = 1 << sb->s_blocksize_bits; + sb->s_magic = V9FS_MAGIC; + sb->s_op = &v9fs_super_ops; + + sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC | + MS_NODIRATIME | MS_NOATIME; +} + +/** + * v9fs_get_sb - mount a superblock + * @fs_type: file system type + * @flags: mount flags + * @dev_name: device name that was mounted + * @data: mount options + * + */ + +static struct super_block *v9fs_get_sb(struct file_system_type + *fs_type, int flags, + const char *dev_name, void *data) +{ + struct super_block *sb = NULL; + struct v9fs_fcall *fcall = NULL; + struct inode *inode = NULL; + struct dentry *root = NULL; + struct v9fs_session_info *v9ses = NULL; + struct v9fs_fid *root_fid = NULL; + int mode = S_IRWXUGO | S_ISVTX; + uid_t uid = current->fsuid; + gid_t gid = current->fsgid; + int stat_result = 0; + int newfid = 0; + int retval = 0; + + dprintk(DEBUG_VFS, " \n"); + + v9ses = kcalloc(1, sizeof(struct v9fs_session_info), GFP_KERNEL); + if (!v9ses) + return ERR_PTR(-ENOMEM); + + if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { + dprintk(DEBUG_ERROR, "problem initiating session\n"); + retval = newfid; + goto free_session; + } + + sb = sget(fs_type, NULL, v9fs_set_super, v9ses); + + v9fs_fill_super(sb, v9ses, flags); + + inode = v9fs_get_inode(sb, S_IFDIR | mode); + if (IS_ERR(inode)) { + retval = PTR_ERR(inode); + goto put_back_sb; + } + + inode->i_uid = uid; + inode->i_gid = gid; + + root = d_alloc_root(inode); + + if (!root) { + retval = -ENOMEM; + goto release_inode; + } + + sb->s_root = root; + + /* Setup the Root Inode */ + root_fid = v9fs_fid_create(root); + if (root_fid == NULL) { + retval = -ENOMEM; + goto release_dentry; + } + + root_fid->fidopen = 0; + root_fid->v9ses = v9ses; + + stat_result = v9fs_t_stat(v9ses, newfid, &fcall); + if (stat_result < 0) { + dprintk(DEBUG_ERROR, "stat error\n"); + v9fs_t_clunk(v9ses, newfid, NULL); + v9fs_put_idpool(newfid, &v9ses->fidpool); + } else { + root_fid->fid = newfid; + root_fid->qid = fcall->params.rstat.stat->qid; + root->d_inode->i_ino = + v9fs_qid2ino(&fcall->params.rstat.stat->qid); + v9fs_mistat2inode(fcall->params.rstat.stat, root->d_inode, sb); + } + + kfree(fcall); + + if (stat_result < 0) { + retval = stat_result; + goto release_dentry; + } + + return sb; + + release_dentry: + dput(sb->s_root); + + release_inode: + iput(inode); + + put_back_sb: + up_write(&sb->s_umount); + deactivate_super(sb); + v9fs_session_close(v9ses); + + free_session: + kfree(v9ses); + + return ERR_PTR(retval); +} + +/** + * v9fs_kill_super - Kill Superblock + * @s: superblock + * + */ + +static void v9fs_kill_super(struct super_block *s) +{ + struct v9fs_session_info *v9ses = s->s_fs_info; + + dprintk(DEBUG_VFS, " %p\n", s); + + v9fs_dentry_release(s->s_root); /* clunk root */ + + kill_anon_super(s); + + v9fs_session_close(v9ses); + kfree(v9ses); + dprintk(DEBUG_VFS, "exiting kill_super\n"); +} + +/** + * v9fs_show_options - Show mount options in /proc/mounts + * @m: seq_file to write to + * @mnt: mount descriptor + * + */ + +static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info; + + if (v9ses->debug != 0) + seq_printf(m, ",debug=%u", v9ses->debug); + if (v9ses->port != V9FS_PORT) + seq_printf(m, ",port=%u", v9ses->port); + if (v9ses->maxdata != 9000) + seq_printf(m, ",msize=%u", v9ses->maxdata); + if (v9ses->afid != ~0) + seq_printf(m, ",afid=%u", v9ses->afid); + if (v9ses->proto == PROTO_UNIX) + seq_puts(m, ",proto=unix"); + if (v9ses->extended == 0) + seq_puts(m, ",noextend"); + if (v9ses->nodev == 1) + seq_puts(m, ",nodevmap"); + seq_printf(m, ",name=%s", v9ses->name); + seq_printf(m, ",aname=%s", v9ses->remotename); + seq_printf(m, ",uid=%u", v9ses->uid); + seq_printf(m, ",gid=%u", v9ses->gid); + return 0; +} + +static struct super_operations v9fs_super_ops = { + .statfs = simple_statfs, + .clear_inode = v9fs_clear_inode, + .show_options = v9fs_show_options, +}; + +struct file_system_type v9fs_fs_type = { + .name = "9P", + .get_sb = v9fs_get_sb, + .kill_sb = v9fs_kill_super, + .owner = THIS_MODULE, +}; -- GitLab From b8cf945b3166c4394386f162a527c9950f396ce2 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:21 -0700 Subject: [PATCH 211/563] [PATCH] v9fs: 9P protocol implementation This part of the patch contains the 9P protocol functions. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/9p.c | 359 ++++++++++++++++++++++++++ fs/9p/9p.h | 341 +++++++++++++++++++++++++ fs/9p/conv.c | 693 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/9p/conv.h | 36 +++ 4 files changed, 1429 insertions(+) create mode 100644 fs/9p/9p.c create mode 100644 fs/9p/9p.h create mode 100644 fs/9p/conv.c create mode 100644 fs/9p/conv.h diff --git a/fs/9p/9p.c b/fs/9p/9p.c new file mode 100644 index 0000000000000..e847f504a47c7 --- /dev/null +++ b/fs/9p/9p.c @@ -0,0 +1,359 @@ +/* + * linux/fs/9p/9p.c + * + * This file contains functions 9P2000 functions + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "9p.h" +#include "mux.h" + +/** + * v9fs_t_version - negotiate protocol parameters with sever + * @v9ses: 9P2000 session information + * @msize: requested max size packet + * @version: requested version.extension string + * @fcall: pointer to response fcall pointer + * + */ + +int +v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, + char *version, struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + + dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version); + msg.id = TVERSION; + msg.params.tversion.msize = msize; + msg.params.tversion.version = version; + + return v9fs_mux_rpc(v9ses, &msg, fcall); +} + +/** + * v9fs_t_attach - mount the server + * @v9ses: 9P2000 session information + * @uname: user name doing the attach + * @aname: remote name being attached to + * @fid: mount fid to attatch to root node + * @afid: authentication fid (in this case result key) + * @fcall: pointer to response fcall pointer + * + */ + +int +v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, + u32 fid, u32 afid, struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + + dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname, + aname, fid, afid); + msg.id = TATTACH; + msg.params.tattach.fid = fid; + msg.params.tattach.afid = afid; + msg.params.tattach.uname = uname; + msg.params.tattach.aname = aname; + + return v9fs_mux_rpc(v9ses, &msg, fcall); +} + +/** + * v9fs_t_clunk - release a fid (finish a transaction) + * @v9ses: 9P2000 session information + * @fid: fid to release + * @fcall: pointer to response fcall pointer + * + */ + +int +v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid, + struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + + dprintk(DEBUG_9P, "fid %d\n", fid); + msg.id = TCLUNK; + msg.params.tclunk.fid = fid; + + return v9fs_mux_rpc(v9ses, &msg, fcall); +} + +/** + * v9fs_v9fs_t_flush - flush a pending transaction + * @v9ses: 9P2000 session information + * @tag: tid to release + * + */ + +int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag) +{ + struct v9fs_fcall msg; + + dprintk(DEBUG_9P, "oldtag %d\n", tag); + msg.id = TFLUSH; + msg.params.tflush.oldtag = tag; + return v9fs_mux_rpc(v9ses, &msg, NULL); +} + +/** + * v9fs_t_stat - read a file's meta-data + * @v9ses: 9P2000 session information + * @fid: fid pointing to file or directory to get info about + * @fcall: pointer to response fcall + * + */ + +int +v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + + dprintk(DEBUG_9P, "fid %d\n", fid); + if (fcall) + *fcall = NULL; + + msg.id = TSTAT; + msg.params.tstat.fid = fid; + return v9fs_mux_rpc(v9ses, &msg, fcall); +} + +/** + * v9fs_t_wstat - write a file's meta-data + * @v9ses: 9P2000 session information + * @fid: fid pointing to file or directory to write info about + * @stat: metadata + * @fcall: pointer to response fcall + * + */ + +int +v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, + struct v9fs_stat *stat, struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + + dprintk(DEBUG_9P, "fid %d length %d\n", fid, (int)stat->length); + msg.id = TWSTAT; + msg.params.twstat.fid = fid; + msg.params.twstat.stat = stat; + + return v9fs_mux_rpc(v9ses, &msg, fcall); +} + +/** + * v9fs_t_walk - walk a fid to a new file or directory + * @v9ses: 9P2000 session information + * @fid: fid to walk + * @newfid: new fid (for clone operations) + * @name: path to walk fid to + * @fcall: pointer to response fcall + * + */ + +/* TODO: support multiple walk */ + +int +v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, + char *name, struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + + dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name); + msg.id = TWALK; + msg.params.twalk.fid = fid; + msg.params.twalk.newfid = newfid; + + if (name) { + msg.params.twalk.nwname = 1; + msg.params.twalk.wnames = &name; + } else { + msg.params.twalk.nwname = 0; + } + + return v9fs_mux_rpc(v9ses, &msg, fcall); +} + +/** + * v9fs_t_open - open a file + * + * @v9ses - 9P2000 session information + * @fid - fid to open + * @mode - mode to open file (R, RW, etc) + * @fcall - pointer to response fcall + * + */ + +int +v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode, + struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + long errorno = -1; + + dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode); + msg.id = TOPEN; + msg.params.topen.fid = fid; + msg.params.topen.mode = mode; + + errorno = v9fs_mux_rpc(v9ses, &msg, fcall); + + return errorno; +} + +/** + * v9fs_t_remove - remove a file or directory + * @v9ses: 9P2000 session information + * @fid: fid to remove + * @fcall: pointer to response fcall + * + */ + +int +v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid, + struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + + dprintk(DEBUG_9P, "fid %d\n", fid); + msg.id = TREMOVE; + msg.params.tremove.fid = fid; + return v9fs_mux_rpc(v9ses, &msg, fcall); +} + +/** + * v9fs_t_create - create a file or directory + * @v9ses: 9P2000 session information + * @fid: fid to create + * @name: name of the file or directory to create + * @perm: permissions to create with + * @mode: mode to open file (R, RW, etc) + * @fcall: pointer to response fcall + * + */ + +int +v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, + u32 perm, u8 mode, struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + + dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n", + fid, name, perm, mode); + + msg.id = TCREATE; + msg.params.tcreate.fid = fid; + msg.params.tcreate.name = name; + msg.params.tcreate.perm = perm; + msg.params.tcreate.mode = mode; + + return v9fs_mux_rpc(v9ses, &msg, fcall); +} + +/** + * v9fs_t_read - read data + * @v9ses: 9P2000 session information + * @fid: fid to read from + * @offset: offset to start read at + * @count: how many bytes to read + * @fcall: pointer to response fcall (with data) + * + */ + +int +v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset, + u32 count, struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + struct v9fs_fcall *rc = NULL; + long errorno = -1; + + dprintk(DEBUG_9P, "fid %d offset 0x%lx count 0x%x\n", fid, + (long unsigned int)offset, count); + msg.id = TREAD; + msg.params.tread.fid = fid; + msg.params.tread.offset = offset; + msg.params.tread.count = count; + errorno = v9fs_mux_rpc(v9ses, &msg, &rc); + + if (!errorno) { + errorno = rc->params.rread.count; + dump_data(rc->params.rread.data, rc->params.rread.count); + } + + if (fcall) + *fcall = rc; + else + kfree(rc); + + return errorno; +} + +/** + * v9fs_t_write - write data + * @v9ses: 9P2000 session information + * @fid: fid to write to + * @offset: offset to start write at + * @count: how many bytes to write + * @fcall: pointer to response fcall + * + */ + +int +v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, + u64 offset, u32 count, void *data, struct v9fs_fcall **fcall) +{ + struct v9fs_fcall msg; + struct v9fs_fcall *rc = NULL; + long errorno = -1; + + dprintk(DEBUG_9P, "fid %d offset 0x%llx count 0x%x\n", fid, + (unsigned long long)offset, count); + dump_data(data, count); + + msg.id = TWRITE; + msg.params.twrite.fid = fid; + msg.params.twrite.offset = offset; + msg.params.twrite.count = count; + msg.params.twrite.data = data; + + errorno = v9fs_mux_rpc(v9ses, &msg, &rc); + + if (!errorno) + errorno = rc->params.rwrite.count; + + if (fcall) + *fcall = rc; + else + kfree(rc); + + return errorno; +} diff --git a/fs/9p/9p.h b/fs/9p/9p.h new file mode 100644 index 0000000000000..f55424216be23 --- /dev/null +++ b/fs/9p/9p.h @@ -0,0 +1,341 @@ +/* + * linux/fs/9p/9p.h + * + * 9P protocol definitions. + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +/* Message Types */ +enum { + TVERSION = 100, + RVERSION, + TAUTH = 102, + RAUTH, + TATTACH = 104, + RATTACH, + TERROR = 106, + RERROR, + TFLUSH = 108, + RFLUSH, + TWALK = 110, + RWALK, + TOPEN = 112, + ROPEN, + TCREATE = 114, + RCREATE, + TREAD = 116, + RREAD, + TWRITE = 118, + RWRITE, + TCLUNK = 120, + RCLUNK, + TREMOVE = 122, + RREMOVE, + TSTAT = 124, + RSTAT, + TWSTAT = 126, + RWSTAT, +}; + +/* modes */ +enum { + V9FS_OREAD = 0x00, + V9FS_OWRITE = 0x01, + V9FS_ORDWR = 0x02, + V9FS_OEXEC = 0x03, + V9FS_OEXCL = 0x04, + V9FS_OTRUNC = 0x10, + V9FS_OREXEC = 0x20, + V9FS_ORCLOSE = 0x40, + V9FS_OAPPEND = 0x80, +}; + +/* permissions */ +enum { + V9FS_DMDIR = 0x80000000, + V9FS_DMAPPEND = 0x40000000, + V9FS_DMEXCL = 0x20000000, + V9FS_DMMOUNT = 0x10000000, + V9FS_DMAUTH = 0x08000000, + V9FS_DMTMP = 0x04000000, + V9FS_DMSYMLINK = 0x02000000, + V9FS_DMLINK = 0x01000000, + /* 9P2000.u extensions */ + V9FS_DMDEVICE = 0x00800000, + V9FS_DMNAMEDPIPE = 0x00200000, + V9FS_DMSOCKET = 0x00100000, + V9FS_DMSETUID = 0x00080000, + V9FS_DMSETGID = 0x00040000, +}; + +/* qid.types */ +enum { + V9FS_QTDIR = 0x80, + V9FS_QTAPPEND = 0x40, + V9FS_QTEXCL = 0x20, + V9FS_QTMOUNT = 0x10, + V9FS_QTAUTH = 0x08, + V9FS_QTTMP = 0x04, + V9FS_QTSYMLINK = 0x02, + V9FS_QTLINK = 0x01, + V9FS_QTFILE = 0x00, +}; + +/* ample room for Twrite/Rread header (iounit) */ +#define V9FS_IOHDRSZ 24 + +/* qids are the unique ID for a file (like an inode */ +struct v9fs_qid { + u8 type; + u32 version; + u64 path; +}; + +/* Plan 9 file metadata (stat) structure */ +struct v9fs_stat { + u16 size; + u16 type; + u32 dev; + struct v9fs_qid qid; + u32 mode; + u32 atime; + u32 mtime; + u64 length; + char *name; + char *uid; + char *gid; + char *muid; + char *extension; /* 9p2000.u extensions */ + u32 n_uid; /* 9p2000.u extensions */ + u32 n_gid; /* 9p2000.u extensions */ + u32 n_muid; /* 9p2000.u extensions */ + char data[0]; +}; + +/* Structures for Protocol Operations */ + +struct Tversion { + u32 msize; + char *version; +}; + +struct Rversion { + u32 msize; + char *version; +}; + +struct Tauth { + u32 afid; + char *uname; + char *aname; +}; + +struct Rauth { + struct v9fs_qid qid; +}; + +struct Rerror { + char *error; + u32 errno; /* 9p2000.u extension */ +}; + +struct Tflush { + u32 oldtag; +}; + +struct Rflush { +}; + +struct Tattach { + u32 fid; + u32 afid; + char *uname; + char *aname; +}; + +struct Rattach { + struct v9fs_qid qid; +}; + +struct Twalk { + u32 fid; + u32 newfid; + u32 nwname; + char **wnames; +}; + +struct Rwalk { + u32 nwqid; + struct v9fs_qid *wqids; +}; + +struct Topen { + u32 fid; + u8 mode; +}; + +struct Ropen { + struct v9fs_qid qid; + u32 iounit; +}; + +struct Tcreate { + u32 fid; + char *name; + u32 perm; + u8 mode; +}; + +struct Rcreate { + struct v9fs_qid qid; + u32 iounit; +}; + +struct Tread { + u32 fid; + u64 offset; + u32 count; +}; + +struct Rread { + u32 count; + u8 *data; +}; + +struct Twrite { + u32 fid; + u64 offset; + u32 count; + u8 *data; +}; + +struct Rwrite { + u32 count; +}; + +struct Tclunk { + u32 fid; +}; + +struct Rclunk { +}; + +struct Tremove { + u32 fid; +}; + +struct Rremove { +}; + +struct Tstat { + u32 fid; +}; + +struct Rstat { + struct v9fs_stat *stat; +}; + +struct Twstat { + u32 fid; + struct v9fs_stat *stat; +}; + +struct Rwstat { +}; + +/* + * fcall is the primary packet structure + * + */ + +struct v9fs_fcall { + u32 size; + u8 id; + u16 tag; + + union { + struct Tversion tversion; + struct Rversion rversion; + struct Tauth tauth; + struct Rauth rauth; + struct Rerror rerror; + struct Tflush tflush; + struct Rflush rflush; + struct Tattach tattach; + struct Rattach rattach; + struct Twalk twalk; + struct Rwalk rwalk; + struct Topen topen; + struct Ropen ropen; + struct Tcreate tcreate; + struct Rcreate rcreate; + struct Tread tread; + struct Rread rread; + struct Twrite twrite; + struct Rwrite rwrite; + struct Tclunk tclunk; + struct Rclunk rclunk; + struct Tremove tremove; + struct Rremove rremove; + struct Tstat tstat; + struct Rstat rstat; + struct Twstat twstat; + struct Rwstat rwstat; + } params; +}; + +#define FCALL_ERROR(fcall) (fcall ? fcall->params.rerror.error : "") + +int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize, + char *version, struct v9fs_fcall **rcall); + +int v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname, + u32 fid, u32 afid, struct v9fs_fcall **rcall); + +int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid, + struct v9fs_fcall **rcall); + +int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag); + +int v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, + struct v9fs_fcall **rcall); + +int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid, + struct v9fs_stat *stat, struct v9fs_fcall **rcall); + +int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid, + char *name, struct v9fs_fcall **rcall); + +int v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode, + struct v9fs_fcall **rcall); + +int v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid, + struct v9fs_fcall **rcall); + +int v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, + u32 perm, u8 mode, struct v9fs_fcall **rcall); + +int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, + u64 offset, u32 count, struct v9fs_fcall **rcall); + +int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, + u32 count, void *data, struct v9fs_fcall **rcall); diff --git a/fs/9p/conv.c b/fs/9p/conv.c new file mode 100644 index 0000000000000..1554731bd6535 --- /dev/null +++ b/fs/9p/conv.c @@ -0,0 +1,693 @@ +/* + * linux/fs/9p/conv.c + * + * 9P protocol conversion functions + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "9p.h" +#include "conv.h" + +/* + * Buffer to help with string parsing + */ +struct cbuf { + unsigned char *sp; + unsigned char *p; + unsigned char *ep; +}; + +static inline void buf_init(struct cbuf *buf, void *data, int datalen) +{ + buf->sp = buf->p = data; + buf->ep = data + datalen; +} + +static inline int buf_check_overflow(struct cbuf *buf) +{ + return buf->p > buf->ep; +} + +static inline void buf_check_size(struct cbuf *buf, int len) +{ + if (buf->p+len > buf->ep) { + if (buf->p < buf->ep) { + eprintk(KERN_ERR, "buffer overflow\n"); + buf->p = buf->ep + 1; + } + } +} + +static inline void *buf_alloc(struct cbuf *buf, int len) +{ + void *ret = NULL; + + buf_check_size(buf, len); + ret = buf->p; + buf->p += len; + + return ret; +} + +static inline void buf_put_int8(struct cbuf *buf, u8 val) +{ + buf_check_size(buf, 1); + + buf->p[0] = val; + buf->p++; +} + +static inline void buf_put_int16(struct cbuf *buf, u16 val) +{ + buf_check_size(buf, 2); + + *(__le16 *) buf->p = cpu_to_le16(val); + buf->p += 2; +} + +static inline void buf_put_int32(struct cbuf *buf, u32 val) +{ + buf_check_size(buf, 4); + + *(__le32 *)buf->p = cpu_to_le32(val); + buf->p += 4; +} + +static inline void buf_put_int64(struct cbuf *buf, u64 val) +{ + buf_check_size(buf, 8); + + *(__le64 *)buf->p = cpu_to_le64(val); + buf->p += 8; +} + +static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) +{ + buf_check_size(buf, slen + 2); + + buf_put_int16(buf, slen); + memcpy(buf->p, s, slen); + buf->p += slen; +} + +static inline void buf_put_string(struct cbuf *buf, const char *s) +{ + buf_put_stringn(buf, s, strlen(s)); +} + +static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen) +{ + buf_check_size(buf, datalen); + + memcpy(buf->p, data, datalen); + buf->p += datalen; +} + +static inline u8 buf_get_int8(struct cbuf *buf) +{ + u8 ret = 0; + + buf_check_size(buf, 1); + ret = buf->p[0]; + + buf->p++; + + return ret; +} + +static inline u16 buf_get_int16(struct cbuf *buf) +{ + u16 ret = 0; + + buf_check_size(buf, 2); + ret = le16_to_cpu(*(__le16 *)buf->p); + + buf->p += 2; + + return ret; +} + +static inline u32 buf_get_int32(struct cbuf *buf) +{ + u32 ret = 0; + + buf_check_size(buf, 4); + ret = le32_to_cpu(*(__le32 *)buf->p); + + buf->p += 4; + + return ret; +} + +static inline u64 buf_get_int64(struct cbuf *buf) +{ + u64 ret = 0; + + buf_check_size(buf, 8); + ret = le64_to_cpu(*(__le64 *)buf->p); + + buf->p += 8; + + return ret; +} + +static inline int +buf_get_string(struct cbuf *buf, char *data, unsigned int datalen) +{ + + u16 len = buf_get_int16(buf); + buf_check_size(buf, len); + if (len + 1 > datalen) + return 0; + + memcpy(data, buf->p, len); + data[len] = 0; + buf->p += len; + + return len + 1; +} + +static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) +{ + char *ret = NULL; + int n = buf_get_string(buf, sbuf->p, sbuf->ep - sbuf->p); + + if (n > 0) { + ret = sbuf->p; + sbuf->p += n; + } + + return ret; +} + +static inline int buf_get_data(struct cbuf *buf, void *data, int datalen) +{ + buf_check_size(buf, datalen); + + memcpy(data, buf->p, datalen); + buf->p += datalen; + + return datalen; +} + +static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, + int datalen) +{ + char *ret = NULL; + int n = 0; + + buf_check_size(dbuf, datalen); + + n = buf_get_data(buf, dbuf->p, datalen); + + if (n > 0) { + ret = dbuf->p; + dbuf->p += n; + } + + return ret; +} + +/** + * v9fs_size_stat - calculate the size of a variable length stat struct + * @v9ses: session information + * @stat: metadata (stat) structure + * + */ + +static int v9fs_size_stat(struct v9fs_session_info *v9ses, + struct v9fs_stat *stat) +{ + int size = 0; + + if (stat == NULL) { + eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); + return 0; + } + + size = /* 2 + *//* size[2] */ + 2 + /* type[2] */ + 4 + /* dev[4] */ + 1 + /* qid.type[1] */ + 4 + /* qid.vers[4] */ + 8 + /* qid.path[8] */ + 4 + /* mode[4] */ + 4 + /* atime[4] */ + 4 + /* mtime[4] */ + 8 + /* length[8] */ + 8; /* minimum sum of string lengths */ + + if (stat->name) + size += strlen(stat->name); + if (stat->uid) + size += strlen(stat->uid); + if (stat->gid) + size += strlen(stat->gid); + if (stat->muid) + size += strlen(stat->muid); + + if (v9ses->extended) { + size += 4 + /* n_uid[4] */ + 4 + /* n_gid[4] */ + 4 + /* n_muid[4] */ + 2; /* string length of extension[4] */ + if (stat->extension) + size += strlen(stat->extension); + } + + return size; +} + +/** + * serialize_stat - safely format a stat structure for transmission + * @v9ses: session info + * @stat: metadata (stat) structure + * @bufp: buffer to serialize structure into + * + */ + +static int +serialize_stat(struct v9fs_session_info *v9ses, struct v9fs_stat *stat, + struct cbuf *bufp) +{ + buf_put_int16(bufp, stat->size); + buf_put_int16(bufp, stat->type); + buf_put_int32(bufp, stat->dev); + buf_put_int8(bufp, stat->qid.type); + buf_put_int32(bufp, stat->qid.version); + buf_put_int64(bufp, stat->qid.path); + buf_put_int32(bufp, stat->mode); + buf_put_int32(bufp, stat->atime); + buf_put_int32(bufp, stat->mtime); + buf_put_int64(bufp, stat->length); + + buf_put_string(bufp, stat->name); + buf_put_string(bufp, stat->uid); + buf_put_string(bufp, stat->gid); + buf_put_string(bufp, stat->muid); + + if (v9ses->extended) { + buf_put_string(bufp, stat->extension); + buf_put_int32(bufp, stat->n_uid); + buf_put_int32(bufp, stat->n_gid); + buf_put_int32(bufp, stat->n_muid); + } + + if (buf_check_overflow(bufp)) + return 0; + + return stat->size; +} + +/** + * deserialize_stat - safely decode a recieved metadata (stat) structure + * @v9ses: session info + * @bufp: buffer to deserialize + * @stat: metadata (stat) structure + * @dbufp: buffer to deserialize variable strings into + * + */ + +static inline int +deserialize_stat(struct v9fs_session_info *v9ses, struct cbuf *bufp, + struct v9fs_stat *stat, struct cbuf *dbufp) +{ + + stat->size = buf_get_int16(bufp); + stat->type = buf_get_int16(bufp); + stat->dev = buf_get_int32(bufp); + stat->qid.type = buf_get_int8(bufp); + stat->qid.version = buf_get_int32(bufp); + stat->qid.path = buf_get_int64(bufp); + stat->mode = buf_get_int32(bufp); + stat->atime = buf_get_int32(bufp); + stat->mtime = buf_get_int32(bufp); + stat->length = buf_get_int64(bufp); + stat->name = buf_get_stringb(bufp, dbufp); + stat->uid = buf_get_stringb(bufp, dbufp); + stat->gid = buf_get_stringb(bufp, dbufp); + stat->muid = buf_get_stringb(bufp, dbufp); + + if (v9ses->extended) { + stat->extension = buf_get_stringb(bufp, dbufp); + stat->n_uid = buf_get_int32(bufp); + stat->n_gid = buf_get_int32(bufp); + stat->n_muid = buf_get_int32(bufp); + } + + if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) + return 0; + + return stat->size + 2; +} + +/** + * deserialize_statb - wrapper for decoding a received metadata structure + * @v9ses: session info + * @bufp: buffer to deserialize + * @dbufp: buffer to deserialize variable strings into + * + */ + +static inline struct v9fs_stat *deserialize_statb(struct v9fs_session_info + *v9ses, struct cbuf *bufp, + struct cbuf *dbufp) +{ + struct v9fs_stat *ret = buf_alloc(dbufp, sizeof(struct v9fs_stat)); + + if (ret) { + int n = deserialize_stat(v9ses, bufp, ret, dbufp); + if (n <= 0) + return NULL; + } + + return ret; +} + +/** + * v9fs_deserialize_stat - decode a received metadata structure + * @v9ses: session info + * @buf: buffer to deserialize + * @buflen: length of received buffer + * @stat: metadata structure to decode into + * @statlen: length of destination metadata structure + * + */ + +int +v9fs_deserialize_stat(struct v9fs_session_info *v9ses, void *buf, + u32 buflen, struct v9fs_stat *stat, u32 statlen) +{ + struct cbuf buffer; + struct cbuf *bufp = &buffer; + struct cbuf dbuffer; + struct cbuf *dbufp = &dbuffer; + + buf_init(bufp, buf, buflen); + buf_init(dbufp, (char *)stat + sizeof(struct v9fs_stat), + statlen - sizeof(struct v9fs_stat)); + + return deserialize_stat(v9ses, bufp, stat, dbufp); +} + +static inline int +v9fs_size_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall) +{ + int size = 4 + 1 + 2; /* size[4] msg[1] tag[2] */ + int i = 0; + + switch (fcall->id) { + default: + eprintk(KERN_ERR, "bad msg type %d\n", fcall->id); + return 0; + case TVERSION: /* msize[4] version[s] */ + size += 4 + 2 + strlen(fcall->params.tversion.version); + break; + case TAUTH: /* afid[4] uname[s] aname[s] */ + size += 4 + 2 + strlen(fcall->params.tauth.uname) + + 2 + strlen(fcall->params.tauth.aname); + break; + case TFLUSH: /* oldtag[2] */ + size += 2; + break; + case TATTACH: /* fid[4] afid[4] uname[s] aname[s] */ + size += 4 + 4 + 2 + strlen(fcall->params.tattach.uname) + + 2 + strlen(fcall->params.tattach.aname); + break; + case TWALK: /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ + size += 4 + 4 + 2; + /* now compute total for the array of names */ + for (i = 0; i < fcall->params.twalk.nwname; i++) + size += 2 + strlen(fcall->params.twalk.wnames[i]); + break; + case TOPEN: /* fid[4] mode[1] */ + size += 4 + 1; + break; + case TCREATE: /* fid[4] name[s] perm[4] mode[1] */ + size += 4 + 2 + strlen(fcall->params.tcreate.name) + 4 + 1; + break; + case TREAD: /* fid[4] offset[8] count[4] */ + size += 4 + 8 + 4; + break; + case TWRITE: /* fid[4] offset[8] count[4] data[count] */ + size += 4 + 8 + 4 + fcall->params.twrite.count; + break; + case TCLUNK: /* fid[4] */ + size += 4; + break; + case TREMOVE: /* fid[4] */ + size += 4; + break; + case TSTAT: /* fid[4] */ + size += 4; + break; + case TWSTAT: /* fid[4] stat[n] */ + fcall->params.twstat.stat->size = + v9fs_size_stat(v9ses, fcall->params.twstat.stat); + size += 4 + 2 + 2 + fcall->params.twstat.stat->size; + } + return size; +} + +/* + * v9fs_serialize_fcall - marshall fcall struct into a packet + * @v9ses: session information + * @fcall: structure to convert + * @data: buffer to serialize fcall into + * @datalen: length of buffer to serialize fcall into + * + */ + +int +v9fs_serialize_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall, + void *data, u32 datalen) +{ + int i = 0; + struct v9fs_stat *stat = NULL; + struct cbuf buffer; + struct cbuf *bufp = &buffer; + + buf_init(bufp, data, datalen); + + if (!fcall) { + eprintk(KERN_ERR, "no fcall\n"); + return -EINVAL; + } + + fcall->size = v9fs_size_fcall(v9ses, fcall); + + buf_put_int32(bufp, fcall->size); + buf_put_int8(bufp, fcall->id); + buf_put_int16(bufp, fcall->tag); + + dprintk(DEBUG_CONV, "size %d id %d tag %d\n", fcall->size, fcall->id, + fcall->tag); + + /* now encode it */ + switch (fcall->id) { + default: + eprintk(KERN_ERR, "bad msg type: %d\n", fcall->id); + return -EPROTO; + case TVERSION: + buf_put_int32(bufp, fcall->params.tversion.msize); + buf_put_string(bufp, fcall->params.tversion.version); + break; + case TAUTH: + buf_put_int32(bufp, fcall->params.tauth.afid); + buf_put_string(bufp, fcall->params.tauth.uname); + buf_put_string(bufp, fcall->params.tauth.aname); + break; + case TFLUSH: + buf_put_int16(bufp, fcall->params.tflush.oldtag); + break; + case TATTACH: + buf_put_int32(bufp, fcall->params.tattach.fid); + buf_put_int32(bufp, fcall->params.tattach.afid); + buf_put_string(bufp, fcall->params.tattach.uname); + buf_put_string(bufp, fcall->params.tattach.aname); + break; + case TWALK: + buf_put_int32(bufp, fcall->params.twalk.fid); + buf_put_int32(bufp, fcall->params.twalk.newfid); + buf_put_int16(bufp, fcall->params.twalk.nwname); + for (i = 0; i < fcall->params.twalk.nwname; i++) + buf_put_string(bufp, fcall->params.twalk.wnames[i]); + break; + case TOPEN: + buf_put_int32(bufp, fcall->params.topen.fid); + buf_put_int8(bufp, fcall->params.topen.mode); + break; + case TCREATE: + buf_put_int32(bufp, fcall->params.tcreate.fid); + buf_put_string(bufp, fcall->params.tcreate.name); + buf_put_int32(bufp, fcall->params.tcreate.perm); + buf_put_int8(bufp, fcall->params.tcreate.mode); + break; + case TREAD: + buf_put_int32(bufp, fcall->params.tread.fid); + buf_put_int64(bufp, fcall->params.tread.offset); + buf_put_int32(bufp, fcall->params.tread.count); + break; + case TWRITE: + buf_put_int32(bufp, fcall->params.twrite.fid); + buf_put_int64(bufp, fcall->params.twrite.offset); + buf_put_int32(bufp, fcall->params.twrite.count); + buf_put_data(bufp, fcall->params.twrite.data, + fcall->params.twrite.count); + break; + case TCLUNK: + buf_put_int32(bufp, fcall->params.tclunk.fid); + break; + case TREMOVE: + buf_put_int32(bufp, fcall->params.tremove.fid); + break; + case TSTAT: + buf_put_int32(bufp, fcall->params.tstat.fid); + break; + case TWSTAT: + buf_put_int32(bufp, fcall->params.twstat.fid); + stat = fcall->params.twstat.stat; + + buf_put_int16(bufp, stat->size + 2); + serialize_stat(v9ses, stat, bufp); + break; + } + + if (buf_check_overflow(bufp)) + return -EIO; + + return fcall->size; +} + +/** + * deserialize_fcall - unmarshal a response + * @v9ses: session information + * @msgsize: size of rcall message + * @buf: recieved buffer + * @buflen: length of received buffer + * @rcall: fcall structure to populate + * @rcalllen: length of fcall structure to populate + * + */ + +int +v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, + void *buf, u32 buflen, struct v9fs_fcall *rcall, + int rcalllen) +{ + + struct cbuf buffer; + struct cbuf *bufp = &buffer; + struct cbuf dbuffer; + struct cbuf *dbufp = &dbuffer; + int i = 0; + + buf_init(bufp, buf, buflen); + buf_init(dbufp, (char *)rcall + sizeof(struct v9fs_fcall), + rcalllen - sizeof(struct v9fs_fcall)); + + rcall->size = msgsize; + rcall->id = buf_get_int8(bufp); + rcall->tag = buf_get_int16(bufp); + + dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, + rcall->tag); + switch (rcall->id) { + default: + eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); + return -EPROTO; + case RVERSION: + rcall->params.rversion.msize = buf_get_int32(bufp); + rcall->params.rversion.version = buf_get_stringb(bufp, dbufp); + break; + case RFLUSH: + break; + case RATTACH: + rcall->params.rattach.qid.type = buf_get_int8(bufp); + rcall->params.rattach.qid.version = buf_get_int32(bufp); + rcall->params.rattach.qid.path = buf_get_int64(bufp); + break; + case RWALK: + rcall->params.rwalk.nwqid = buf_get_int16(bufp); + rcall->params.rwalk.wqids = buf_alloc(bufp, + rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); + if (rcall->params.rwalk.wqids) + for (i = 0; i < rcall->params.rwalk.nwqid; i++) { + rcall->params.rwalk.wqids[i].type = + buf_get_int8(bufp); + rcall->params.rwalk.wqids[i].version = + buf_get_int16(bufp); + rcall->params.rwalk.wqids[i].path = + buf_get_int64(bufp); + } + break; + case ROPEN: + rcall->params.ropen.qid.type = buf_get_int8(bufp); + rcall->params.ropen.qid.version = buf_get_int32(bufp); + rcall->params.ropen.qid.path = buf_get_int64(bufp); + rcall->params.ropen.iounit = buf_get_int32(bufp); + break; + case RCREATE: + rcall->params.rcreate.qid.type = buf_get_int8(bufp); + rcall->params.rcreate.qid.version = buf_get_int32(bufp); + rcall->params.rcreate.qid.path = buf_get_int64(bufp); + rcall->params.rcreate.iounit = buf_get_int32(bufp); + break; + case RREAD: + rcall->params.rread.count = buf_get_int32(bufp); + rcall->params.rread.data = buf_get_datab(bufp, dbufp, + rcall->params.rread.count); + break; + case RWRITE: + rcall->params.rwrite.count = buf_get_int32(bufp); + break; + case RCLUNK: + break; + case RREMOVE: + break; + case RSTAT: + buf_get_int16(bufp); + rcall->params.rstat.stat = + deserialize_statb(v9ses, bufp, dbufp); + break; + case RWSTAT: + break; + case RERROR: + rcall->params.rerror.error = buf_get_stringb(bufp, dbufp); + if (v9ses->extended) + rcall->params.rerror.errno = buf_get_int16(bufp); + break; + } + + if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) + return -EIO; + + return rcall->size; +} diff --git a/fs/9p/conv.h b/fs/9p/conv.h new file mode 100644 index 0000000000000..ee849613c61a5 --- /dev/null +++ b/fs/9p/conv.h @@ -0,0 +1,36 @@ +/* + * linux/fs/9p/conv.h + * + * 9P protocol conversion definitions + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +int v9fs_deserialize_stat(struct v9fs_session_info *, void *buf, + u32 buflen, struct v9fs_stat *stat, u32 statlen); +int v9fs_serialize_fcall(struct v9fs_session_info *, struct v9fs_fcall *tcall, + void *buf, u32 buflen); +int v9fs_deserialize_fcall(struct v9fs_session_info *, u32 msglen, + void *buf, u32 buflen, struct v9fs_fcall *rcall, + int rcalllen); + +/* this one is actually in error.c right now */ +int v9fs_errstr2errno(char *errstr); -- GitLab From 426cc91aa651b50713d06d45e5c3c3e90cfd40d9 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:22 -0700 Subject: [PATCH 212/563] [PATCH] v9fs: transport modules This part of the patch contains transport routines. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Latchesar Ionkov <lucho@ionkov.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/mux.c | 440 +++++++++++++++++++++++++++++++++++++++++++++ fs/9p/mux.h | 39 ++++ fs/9p/trans_fd.c | 172 ++++++++++++++++++ fs/9p/trans_sock.c | 282 +++++++++++++++++++++++++++++ fs/9p/transport.h | 46 +++++ fs/9p/v9fs.c | 5 - 6 files changed, 979 insertions(+), 5 deletions(-) create mode 100644 fs/9p/mux.c create mode 100644 fs/9p/mux.h create mode 100644 fs/9p/trans_fd.c create mode 100644 fs/9p/trans_sock.c create mode 100644 fs/9p/transport.h diff --git a/fs/9p/mux.c b/fs/9p/mux.c new file mode 100644 index 0000000000000..8ebc1af2c245f --- /dev/null +++ b/fs/9p/mux.c @@ -0,0 +1,440 @@ +/* + * linux/fs/9p/mux.c + * + * Protocol Multiplexer + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kthread.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "9p.h" +#include "transport.h" +#include "conv.h" +#include "mux.h" + +/** + * dprintcond - print condition of session info + * @v9ses: session info structure + * @req: RPC request structure + * + */ + +static inline int +dprintcond(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req) +{ + dprintk(DEBUG_MUX, "condition: %d, %p\n", v9ses->transport->status, + req->rcall); + return 0; +} + +/** + * xread - force read of a certain number of bytes + * @v9ses: session info structure + * @ptr: pointer to buffer + * @sz: number of bytes to read + * + * Chuck Cranor CS-533 project1 + */ + +static int xread(struct v9fs_session_info *v9ses, void *ptr, unsigned long sz) +{ + int rd = 0; + int ret = 0; + while (rd < sz) { + ret = v9ses->transport->read(v9ses->transport, ptr, sz - rd); + if (ret <= 0) { + dprintk(DEBUG_ERROR, "xread errno %d\n", ret); + return ret; + } + rd += ret; + ptr += ret; + } + return (rd); +} + +/** + * read_message - read a full 9P2000 fcall packet + * @v9ses: session info structure + * @rcall: fcall structure to read into + * @rcalllen: size of fcall buffer + * + */ + +static int +read_message(struct v9fs_session_info *v9ses, + struct v9fs_fcall *rcall, int rcalllen) +{ + unsigned char buf[4]; + void *data; + int size = 0; + int res = 0; + + res = xread(v9ses, buf, sizeof(buf)); + if (res < 0) { + dprintk(DEBUG_ERROR, + "Reading of count field failed returned: %d\n", res); + return res; + } + + if (res < 4) { + dprintk(DEBUG_ERROR, + "Reading of count field failed returned: %d\n", res); + return -EIO; + } + + size = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); + dprintk(DEBUG_MUX, "got a packet count: %d\n", size); + + /* adjust for the four bytes of size */ + size -= 4; + + if (size > v9ses->maxdata) { + dprintk(DEBUG_ERROR, "packet too big: %d\n", size); + return -E2BIG; + } + + data = kmalloc(size, GFP_KERNEL); + if (!data) { + eprintk(KERN_WARNING, "out of memory\n"); + return -ENOMEM; + } + + res = xread(v9ses, data, size); + if (res < size) { + dprintk(DEBUG_ERROR, "Reading of fcall failed returned: %d\n", + res); + kfree(data); + return res; + } + + /* we now have an in-memory string that is the reply. + * deserialize it. There is very little to go wrong at this point + * save for v9fs_alloc errors. + */ + res = v9fs_deserialize_fcall(v9ses, size, data, v9ses->maxdata, + rcall, rcalllen); + + kfree(data); + + if (res < 0) + return res; + + return 0; +} + +/** + * v9fs_recv - receive an RPC response for a particular tag + * @v9ses: session info structure + * @req: RPC request structure + * + */ + +static int v9fs_recv(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req) +{ + int ret = 0; + + dprintk(DEBUG_MUX, "waiting for response: %d\n", req->tcall->tag); + ret = wait_event_interruptible(v9ses->read_wait, + ((v9ses->transport->status != Connected) || + (req->rcall != 0) || dprintcond(v9ses, req))); + + dprintk(DEBUG_MUX, "got it: rcall %p\n", req->rcall); + if (v9ses->transport->status == Disconnected) + return -ECONNRESET; + + if (ret == 0) { + spin_lock(&v9ses->muxlock); + list_del(&req->next); + spin_unlock(&v9ses->muxlock); + } + + return ret; +} + +/** + * v9fs_send - send a 9P request + * @v9ses: session info structure + * @req: RPC request to send + * + */ + +static int v9fs_send(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req) +{ + int ret = -1; + void *data = NULL; + struct v9fs_fcall *tcall = req->tcall; + + data = kmalloc(v9ses->maxdata + V9FS_IOHDRSZ, GFP_KERNEL); + if (!data) + return -ENOMEM; + + tcall->size = 0; /* enforce size recalculation */ + ret = + v9fs_serialize_fcall(v9ses, tcall, data, + v9ses->maxdata + V9FS_IOHDRSZ); + if (ret < 0) + goto free_data; + + spin_lock(&v9ses->muxlock); + list_add(&req->next, &v9ses->mux_fcalls); + spin_unlock(&v9ses->muxlock); + + dprintk(DEBUG_MUX, "sending message: tag %d size %d\n", tcall->tag, + tcall->size); + ret = v9ses->transport->write(v9ses->transport, data, tcall->size); + + if (ret != tcall->size) { + spin_lock(&v9ses->muxlock); + list_del(&req->next); + kfree(req->rcall); + + spin_unlock(&v9ses->muxlock); + if (ret >= 0) + ret = -EREMOTEIO; + } else + ret = 0; + + free_data: + kfree(data); + return ret; +} + +/** + * v9fs_mux_rpc - send a request, receive a response + * @v9ses: session info structure + * @tcall: fcall to send + * @rcall: buffer to place response into + * + */ + +long +v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall, + struct v9fs_fcall **rcall) +{ + int tid = -1; + struct v9fs_fcall *fcall = NULL; + struct v9fs_rpcreq req; + int ret = -1; + + if (!v9ses) + return -EINVAL; + + if (rcall) + *rcall = NULL; + + if (tcall->id != TVERSION) { + tid = v9fs_get_idpool(&v9ses->tidpool); + if (tid < 0) + return -ENOMEM; + } + + tcall->tag = tid; + + req.tcall = tcall; + req.rcall = NULL; + + ret = v9fs_send(v9ses, &req); + + if (ret < 0) { + if (tcall->id != TVERSION) + v9fs_put_idpool(tid, &v9ses->tidpool); + dprintk(DEBUG_MUX, "error %d\n", ret); + return ret; + } + + ret = v9fs_recv(v9ses, &req); + + fcall = req.rcall; + + dprintk(DEBUG_MUX, "received: tag=%x, ret=%d\n", tcall->tag, ret); + if (ret == -ERESTARTSYS) { + if (v9ses->transport->status != Disconnected + && tcall->id != TFLUSH) { + unsigned long flags; + + dprintk(DEBUG_MUX, "flushing the tag: %d\n", + tcall->tag); + clear_thread_flag(TIF_SIGPENDING); + v9fs_t_flush(v9ses, tcall->tag); + spin_lock_irqsave(¤t->sighand->siglock, flags); + recalc_sigpending(); + spin_unlock_irqrestore(¤t->sighand->siglock, + flags); + dprintk(DEBUG_MUX, "flushing done\n"); + } + + goto release_req; + } else if (ret < 0) + goto release_req; + + if (!fcall) + ret = -EIO; + else { + if (fcall->id == RERROR) { + ret = v9fs_errstr2errno(fcall->params.rerror.error); + if (ret == 0) { /* string match failed */ + if (fcall->params.rerror.errno) + ret = -(fcall->params.rerror.errno); + else + ret = -ESERVERFAULT; + } + } else if (fcall->id != tcall->id + 1) { + dprintk(DEBUG_ERROR, + "fcall mismatch: expected %d, got %d\n", + tcall->id + 1, fcall->id); + ret = -EIO; + } + } + + release_req: + if (tcall->id != TVERSION) + v9fs_put_idpool(tid, &v9ses->tidpool); + if (rcall) + *rcall = fcall; + else + kfree(fcall); + + return ret; +} + +/** + * v9fs_recvproc - kproc to handle demultiplexing responses + * @data: session info structure + * + */ + +static int v9fs_recvproc(void *data) +{ + struct v9fs_session_info *v9ses = (struct v9fs_session_info *)data; + struct v9fs_fcall *rcall = NULL; + struct v9fs_rpcreq *rptr; + struct v9fs_rpcreq *req; + struct v9fs_rpcreq *rreq; + int err = 0; + + allow_signal(SIGKILL); + set_current_state(TASK_INTERRUPTIBLE); + complete(&v9ses->proccmpl); + while (!kthread_should_stop() && err >= 0) { + req = rptr = rreq = NULL; + + rcall = kmalloc(v9ses->maxdata + V9FS_IOHDRSZ, GFP_KERNEL); + if (!rcall) { + eprintk(KERN_ERR, "no memory for buffers\n"); + break; + } + + err = read_message(v9ses, rcall, v9ses->maxdata + V9FS_IOHDRSZ); + if (err < 0) { + kfree(rcall); + break; + } + spin_lock(&v9ses->muxlock); + list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { + if (rreq->tcall->tag == rcall->tag) { + req = rreq; + req->rcall = rcall; + break; + } + } + + if (req && (req->tcall->id == TFLUSH)) { + struct v9fs_rpcreq *treq = NULL; + list_for_each_entry_safe(treq, rptr, &v9ses->mux_fcalls, next) { + if (treq->tcall->tag == + req->tcall->params.tflush.oldtag) { + list_del(&rptr->next); + kfree(treq->rcall); + break; + } + } + } + + spin_unlock(&v9ses->muxlock); + + if (!req) { + dprintk(DEBUG_ERROR, + "unexpected response: id %d tag %d\n", + rcall->id, rcall->tag); + + kfree(rcall); + } + + wake_up_all(&v9ses->read_wait); + set_current_state(TASK_INTERRUPTIBLE); + } + + /* Inform all pending processes about the failure */ + wake_up_all(&v9ses->read_wait); + + if (signal_pending(current)) + complete(&v9ses->proccmpl); + + dprintk(DEBUG_MUX, "recvproc: end\n"); + v9ses->recvproc = NULL; + + return err >= 0; +} + +/** + * v9fs_mux_init - initialize multiplexer (spawn kproc) + * @v9ses: session info structure + * @dev_name: mount device information (to create unique kproc) + * + */ + +int v9fs_mux_init(struct v9fs_session_info *v9ses, const char *dev_name) +{ + char procname[60]; + + strncpy(procname, dev_name, sizeof(procname)); + procname[sizeof(procname) - 1] = 0; + + init_waitqueue_head(&v9ses->read_wait); + init_completion(&v9ses->fcread); + init_completion(&v9ses->proccmpl); + spin_lock_init(&v9ses->muxlock); + INIT_LIST_HEAD(&v9ses->mux_fcalls); + v9ses->recvproc = NULL; + v9ses->curfcall = NULL; + + v9ses->recvproc = kthread_create(v9fs_recvproc, v9ses, + "v9fs_recvproc %s", procname); + + if (IS_ERR(v9ses->recvproc)) { + eprintk(KERN_ERR, "cannot create receiving thread\n"); + v9fs_session_close(v9ses); + return -ECONNABORTED; + } + + wake_up_process(v9ses->recvproc); + wait_for_completion(&v9ses->proccmpl); + + return 0; +} diff --git a/fs/9p/mux.h b/fs/9p/mux.h new file mode 100644 index 0000000000000..d7d8fa1c15291 --- /dev/null +++ b/fs/9p/mux.h @@ -0,0 +1,39 @@ +/* + * linux/fs/9p/mux.h + * + * Multiplexer Definitions + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +/* structure to manage each RPC transaction */ + +struct v9fs_rpcreq { + struct v9fs_fcall *tcall; + struct v9fs_fcall *rcall; + + /* XXX - could we put scatter/gather buffers here? */ + + struct list_head next; +}; + +int v9fs_mux_init(struct v9fs_session_info *v9ses, const char *dev_name); +long v9fs_mux_rpc(struct v9fs_session_info *v9ses, + struct v9fs_fcall *tcall, struct v9fs_fcall **rcall); diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c new file mode 100644 index 0000000000000..63b58ce98ff45 --- /dev/null +++ b/fs/9p/trans_fd.c @@ -0,0 +1,172 @@ +/* + * linux/fs/9p/trans_fd.c + * + * File Descriptor Transport Layer + * + * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/net.h> +#include <linux/ipv6.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/un.h> +#include <asm/uaccess.h> +#include <linux/inet.h> +#include <linux/idr.h> +#include <linux/file.h> + +#include "debug.h" +#include "v9fs.h" +#include "transport.h" + +struct v9fs_trans_fd { + struct file *in_file; + struct file *out_file; +}; + +/** + * v9fs_fd_recv - receive from a socket + * @v9ses: session information + * @v: buffer to receive data into + * @len: size of receive buffer + * + */ + +static int v9fs_fd_recv(struct v9fs_transport *trans, void *v, int len) +{ + struct v9fs_trans_fd *ts = trans ? trans->priv : NULL; + + if (!trans || trans->status != Connected || !ts) + return -EIO; + + return kernel_read(ts->in_file, ts->in_file->f_pos, v, len); +} + +/** + * v9fs_fd_send - send to a socket + * @v9ses: session information + * @v: buffer to send data from + * @len: size of send buffer + * + */ + +static int v9fs_fd_send(struct v9fs_transport *trans, void *v, int len) +{ + struct v9fs_trans_fd *ts = trans ? trans->priv : NULL; + mm_segment_t oldfs = get_fs(); + int ret = 0; + + if (!trans || trans->status != Connected || !ts) + return -EIO; + + set_fs(get_ds()); + /* The cast to a user pointer is valid due to the set_fs() */ + ret = vfs_write(ts->out_file, (void __user *)v, len, &ts->out_file->f_pos); + set_fs(oldfs); + + return ret; +} + +/** + * v9fs_fd_init - initialize file descriptor transport + * @v9ses: session information + * @addr: address of server to mount + * @data: mount options + * + */ + +static int +v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr, char *data) +{ + struct v9fs_trans_fd *ts = NULL; + struct v9fs_transport *trans = v9ses->transport; + + if((v9ses->wfdno == ~0) || (v9ses->rfdno == ~0)) { + printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); + return -ENOPROTOOPT; + } + + sema_init(&trans->writelock, 1); + sema_init(&trans->readlock, 1); + + ts = kmalloc(sizeof(struct v9fs_trans_fd), GFP_KERNEL); + + if (!ts) + return -ENOMEM; + + ts->in_file = fget( v9ses->rfdno ); + ts->out_file = fget( v9ses->wfdno ); + + if (!ts->in_file || !ts->out_file) { + if (ts->in_file) + fput(ts->in_file); + + if (ts->out_file) + fput(ts->out_file); + + kfree(ts); + return -EIO; + } + + trans->priv = ts; + trans->status = Connected; + + return 0; +} + + +/** + * v9fs_fd_close - shutdown file descriptor + * @trans: private socket structure + * + */ + +static void v9fs_fd_close(struct v9fs_transport *trans) +{ + struct v9fs_trans_fd *ts; + + if (!trans) + return; + + trans->status = Disconnected; + ts = trans->priv; + + if (!ts) + return; + + if (ts->in_file) + fput(ts->in_file); + + if (ts->out_file) + fput(ts->out_file); + + kfree(ts); +} + +struct v9fs_transport v9fs_trans_fd = { + .init = v9fs_fd_init, + .write = v9fs_fd_send, + .read = v9fs_fd_recv, + .close = v9fs_fd_close, +}; + diff --git a/fs/9p/trans_sock.c b/fs/9p/trans_sock.c new file mode 100644 index 0000000000000..081d1c8478030 --- /dev/null +++ b/fs/9p/trans_sock.c @@ -0,0 +1,282 @@ +/* + * linux/fs/9p/trans_socket.c + * + * Socket Transport Layer + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> + * Copyright (C) 1995, 1996 by Olaf Kirch <okir@monad.swb.de> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/net.h> +#include <linux/ipv6.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/un.h> +#include <asm/uaccess.h> +#include <linux/inet.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "transport.h" + +#define V9FS_PORT 564 + +struct v9fs_trans_sock { + struct socket *s; +}; + +/** + * v9fs_sock_recv - receive from a socket + * @v9ses: session information + * @v: buffer to receive data into + * @len: size of receive buffer + * + */ + +static int v9fs_sock_recv(struct v9fs_transport *trans, void *v, int len) +{ + struct msghdr msg; + struct kvec iov; + int result; + mm_segment_t oldfs; + struct v9fs_trans_sock *ts = trans ? trans->priv : NULL; + + if (trans->status == Disconnected) + return -EREMOTEIO; + + result = -EINVAL; + + oldfs = get_fs(); + set_fs(get_ds()); + + iov.iov_base = v; + iov.iov_len = len; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_namelen = 0; + msg.msg_flags = MSG_NOSIGNAL; + + result = kernel_recvmsg(ts->s, &msg, &iov, 1, len, 0); + + dprintk(DEBUG_TRANS, "socket state %d\n", ts->s->state); + set_fs(oldfs); + + if (result <= 0) { + if (result != -ERESTARTSYS) + trans->status = Disconnected; + } + + return result; +} + +/** + * v9fs_sock_send - send to a socket + * @v9ses: session information + * @v: buffer to send data from + * @len: size of send buffer + * + */ + +static int v9fs_sock_send(struct v9fs_transport *trans, void *v, int len) +{ + struct kvec iov; + struct msghdr msg; + int result = -1; + mm_segment_t oldfs; + struct v9fs_trans_sock *ts = trans ? trans->priv : NULL; + + dprintk(DEBUG_TRANS, "Sending packet size %d (%x)\n", len, len); + dump_data(v, len); + + down(&trans->writelock); + + oldfs = get_fs(); + set_fs(get_ds()); + iov.iov_base = v; + iov.iov_len = len; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_namelen = 0; + msg.msg_flags = MSG_NOSIGNAL; + result = kernel_sendmsg(ts->s, &msg, &iov, 1, len); + set_fs(oldfs); + + if (result < 0) { + if (result != -ERESTARTSYS) + trans->status = Disconnected; + } + + up(&trans->writelock); + return result; +} + +/** + * v9fs_tcp_init - initialize TCP socket + * @v9ses: session information + * @addr: address of server to mount + * @data: mount options + * + */ + +static int +v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr, char *data) +{ + struct socket *csocket = NULL; + struct sockaddr_in sin_server; + int rc = 0; + struct v9fs_trans_sock *ts = NULL; + struct v9fs_transport *trans = v9ses->transport; + + sema_init(&trans->writelock, 1); + sema_init(&trans->readlock, 1); + + ts = kmalloc(sizeof(struct v9fs_trans_sock), GFP_KERNEL); + + if (!ts) + return -ENOMEM; + + trans->priv = ts; + ts->s = NULL; + + if (!addr) + return -EINVAL; + + dprintk(DEBUG_TRANS, "Connecting to %s\n", addr); + + sin_server.sin_family = AF_INET; + sin_server.sin_addr.s_addr = in_aton(addr); + sin_server.sin_port = htons(v9ses->port); + sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); + rc = csocket->ops->connect(csocket, + (struct sockaddr *)&sin_server, + sizeof(struct sockaddr_in), 0); + if (rc < 0) { + eprintk(KERN_ERR, + "v9fs_trans_tcp: problem connecting socket to %s\n", + addr); + return rc; + } + csocket->sk->sk_allocation = GFP_NOIO; + ts->s = csocket; + trans->status = Connected; + + return 0; +} + +/** + * v9fs_unix_init - initialize UNIX domain socket + * @v9ses: session information + * @dev_name: path to named pipe + * @data: mount options + * + */ + +static int +v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name, + char *data) +{ + int rc; + struct socket *csocket; + struct sockaddr_un sun_server; + struct v9fs_transport *trans; + struct v9fs_trans_sock *ts; + + rc = 0; + csocket = NULL; + trans = v9ses->transport; + + if (strlen(dev_name) > UNIX_PATH_MAX) { + eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n", + dev_name); + return -ENOMEM; + } + + ts = kmalloc(sizeof(struct v9fs_trans_sock), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + trans->priv = ts; + ts->s = NULL; + + sema_init(&trans->writelock, 1); + sema_init(&trans->readlock, 1); + + sun_server.sun_family = PF_UNIX; + strcpy(sun_server.sun_path, dev_name); + sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); + rc = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, + sizeof(struct sockaddr_un) - 1, 0); /* -1 *is* important */ + if (rc < 0) { + eprintk(KERN_ERR, + "v9fs_trans_unix: problem connecting socket: %s: %d\n", + dev_name, rc); + return rc; + } + csocket->sk->sk_allocation = GFP_NOIO; + ts->s = csocket; + trans->status = Connected; + + return 0; +} + +/** + * v9fs_sock_close - shutdown socket + * @trans: private socket structure + * + */ + +static void v9fs_sock_close(struct v9fs_transport *trans) +{ + struct v9fs_trans_sock *ts = trans ? trans->priv : NULL; + + if ((ts) && (ts->s)) { + dprintk(DEBUG_TRANS, "closing the socket %p\n", ts->s); + sock_release(ts->s); + ts->s = NULL; + trans->status = Disconnected; + dprintk(DEBUG_TRANS, "socket closed\n"); + } + + kfree(ts); +} + +struct v9fs_transport v9fs_trans_tcp = { + .init = v9fs_tcp_init, + .write = v9fs_sock_send, + .read = v9fs_sock_recv, + .close = v9fs_sock_close, +}; + +struct v9fs_transport v9fs_trans_unix = { + .init = v9fs_unix_init, + .write = v9fs_sock_send, + .read = v9fs_sock_recv, + .close = v9fs_sock_close, +}; diff --git a/fs/9p/transport.h b/fs/9p/transport.h new file mode 100644 index 0000000000000..9e9cd418efd54 --- /dev/null +++ b/fs/9p/transport.h @@ -0,0 +1,46 @@ +/* + * linux/fs/9p/transport.h + * + * Transport Definition + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +enum v9fs_transport_status { + Connected, + Disconnected, + Hung, +}; + +struct v9fs_transport { + enum v9fs_transport_status status; + struct semaphore writelock; + struct semaphore readlock; + void *priv; + + int (*init) (struct v9fs_session_info *, const char *, char *); + int (*write) (struct v9fs_transport *, void *, int); + int (*read) (struct v9fs_transport *, void *, int); + void (*close) (struct v9fs_transport *); +}; + +extern struct v9fs_transport v9fs_trans_tcp; +extern struct v9fs_transport v9fs_trans_unix; +extern struct v9fs_transport v9fs_trans_fd; diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 14d663ebfcbcc..a573b751dd9a6 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -296,11 +296,6 @@ v9fs_session_init(struct v9fs_session_info *v9ses, case PROTO_FD: trans_proto = &v9fs_trans_fd; *v9ses->remotename = 0; - if((v9ses->wfdno == ~0) || (v9ses->rfdno == ~0)) { - printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); - retval = -ENOPROTOOPT; - goto SessCleanUp; - } break; default: printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); -- GitLab From 322b329ab787de5f45abca9c9eabfd33bc5927e8 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:23 -0700 Subject: [PATCH 213/563] [PATCH] v9fs: Support to force umount Support for force umount Signed-off-by: Latchesar Ionkov <lucho@ionkov.net> Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/mux.c | 20 ++++++++++++++++++++ fs/9p/mux.h | 1 + fs/9p/v9fs.c | 9 +++++++++ fs/9p/v9fs.h | 4 +--- fs/9p/vfs_super.c | 9 +++++++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 8ebc1af2c245f..0854bef58c166 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -323,6 +323,26 @@ v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall, return ret; } +/** + * v9fs_mux_cancel_requests - cancels all pending requests + * + * @v9ses: session info structure + * @err: error code to return to the requests + */ +void v9fs_mux_cancel_requests(struct v9fs_session_info *v9ses, int err) +{ + struct v9fs_rpcreq *rptr; + struct v9fs_rpcreq *rreq; + + dprintk(DEBUG_MUX, " %d\n", err); + spin_lock(&v9ses->muxlock); + list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { + rreq->err = err; + } + spin_unlock(&v9ses->muxlock); + wake_up_all(&v9ses->read_wait); +} + /** * v9fs_recvproc - kproc to handle demultiplexing responses * @data: session info structure diff --git a/fs/9p/mux.h b/fs/9p/mux.h index d7d8fa1c15291..82ce793af1b57 100644 --- a/fs/9p/mux.h +++ b/fs/9p/mux.h @@ -37,3 +37,4 @@ struct v9fs_rpcreq { int v9fs_mux_init(struct v9fs_session_info *v9ses, const char *dev_name); long v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall, struct v9fs_fcall **rcall); +void v9fs_mux_cancel_requests(struct v9fs_session_info *v9ses, int err); diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index a573b751dd9a6..13bdbbab4387a 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -409,6 +409,15 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) putname(v9ses->remotename); } +/** + * v9fs_session_cancel - mark transport as disconnected + * and cancel all pending requests. + */ +void v9fs_session_cancel(struct v9fs_session_info *v9ses) { + v9ses->transport->status = Disconnected; + v9fs_mux_cancel_requests(v9ses, -EIO); +} + extern int v9fs_error_init(void); /** diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 52203027b1586..45dcef42bdd63 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -89,9 +89,7 @@ struct v9fs_session_info *v9fs_inode2v9ses(struct inode *); void v9fs_session_close(struct v9fs_session_info *v9ses); int v9fs_get_idpool(struct v9fs_idpool *p); void v9fs_put_idpool(int id, struct v9fs_idpool *p); -int v9fs_get_option(char *opts, char *name, char *buf, int buflen); -long long v9fs_get_int_option(char *opts, char *name, long long dflt); -int v9fs_parse_tcp_devname(const char *devname, char **addr, char **remotename); +void v9fs_session_cancel(struct v9fs_session_info *v9ses); #define V9FS_MAGIC 0x01021997 diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index ce0778acc90ab..868f350b2c5fa 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -257,10 +257,19 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt) return 0; } +static void +v9fs_umount_begin(struct super_block *sb) +{ + struct v9fs_session_info *v9ses = sb->s_fs_info; + + v9fs_session_cancel(v9ses); +} + static struct super_operations v9fs_super_ops = { .statfs = simple_statfs, .clear_inode = v9fs_clear_inode, .show_options = v9fs_show_options, + .umount_begin = v9fs_umount_begin, }; struct file_system_type v9fs_fs_type = { -- GitLab From 3ed8491c8a75cefe95b57f7f428a3e2ddd421e97 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:24 -0700 Subject: [PATCH 214/563] [PATCH] v9fs: debug and support routines This part of the patch contains debug and other misc routines. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/debug.h | 70 +++++++++++++++ fs/9p/error.c | 93 +++++++++++++++++++ fs/9p/error.h | 181 +++++++++++++++++++++++++++++++++++++ fs/9p/fid.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/9p/fid.h | 57 ++++++++++++ 5 files changed, 642 insertions(+) create mode 100644 fs/9p/debug.h create mode 100644 fs/9p/error.c create mode 100644 fs/9p/error.h create mode 100644 fs/9p/fid.c create mode 100644 fs/9p/fid.h diff --git a/fs/9p/debug.h b/fs/9p/debug.h new file mode 100644 index 0000000000000..4445f06919d9b --- /dev/null +++ b/fs/9p/debug.h @@ -0,0 +1,70 @@ +/* + * linux/fs/9p/debug.h - V9FS Debug Definitions + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#define DEBUG_ERROR (1<<0) +#define DEBUG_CURRENT (1<<1) +#define DEBUG_9P (1<<2) +#define DEBUG_VFS (1<<3) +#define DEBUG_CONV (1<<4) +#define DEBUG_MUX (1<<5) +#define DEBUG_TRANS (1<<6) +#define DEBUG_SLABS (1<<7) + +#define DEBUG_DUMP_PKT 0 + +extern int v9fs_debug_level; + +#define dprintk(level, format, arg...) \ +do { \ + if((v9fs_debug_level & level)==level) \ + printk(KERN_NOTICE "-- %s (%d): " \ + format , __FUNCTION__, current->pid , ## arg); \ +} while(0) + +#define eprintk(level, format, arg...) \ +do { \ + printk(level "v9fs: %s (%d): " \ + format , __FUNCTION__, current->pid , ## arg); \ +} while(0) + +#if DEBUG_DUMP_PKT +static inline void dump_data(const unsigned char *data, unsigned int datalen) +{ + int i, j; + int len = datalen; + + printk(KERN_DEBUG "data "); + for (i = 0; i < len; i += 4) { + for (j = 0; (j < 4) && (i + j < len); j++) + printk(KERN_DEBUG "%02x", data[i + j]); + printk(KERN_DEBUG " "); + } + printk(KERN_DEBUG "\n"); +} +#else /* DEBUG_DUMP_PKT */ +static inline void dump_data(const unsigned char *data, unsigned int datalen) +{ + +} +#endif /* DEBUG_DUMP_PKT */ diff --git a/fs/9p/error.c b/fs/9p/error.c new file mode 100644 index 0000000000000..fee5d19179c5f --- /dev/null +++ b/fs/9p/error.c @@ -0,0 +1,93 @@ +/* + * linux/fs/9p/error.c + * + * Error string handling + * + * Plan 9 uses error strings, Unix uses error numbers. These functions + * try to help manage that and provide for dynamically adding error + * mappings. + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/list.h> +#include <linux/jhash.h> + +#include "debug.h" +#include "error.h" + +/** + * v9fs_error_init - preload + * @errstr: error string + * + */ + +int v9fs_error_init(void) +{ + struct errormap *c; + int bucket; + + /* initialize hash table */ + for (bucket = 0; bucket < ERRHASHSZ; bucket++) + INIT_HLIST_HEAD(&hash_errmap[bucket]); + + /* load initial error map into hash table */ + for (c = errmap; c->name != NULL; c++) { + bucket = jhash(c->name, strlen(c->name), 0) % ERRHASHSZ; + INIT_HLIST_NODE(&c->list); + hlist_add_head(&c->list, &hash_errmap[bucket]); + } + + return 1; +} + +/** + * errstr2errno - convert error string to error number + * @errstr: error string + * + */ + +int v9fs_errstr2errno(char *errstr) +{ + int errno = 0; + struct hlist_node *p = NULL; + struct errormap *c = NULL; + int bucket = jhash(errstr, strlen(errstr), 0) % ERRHASHSZ; + + hlist_for_each_entry(c, p, &hash_errmap[bucket], list) { + if (!strcmp(c->name, errstr)) { + errno = c->val; + break; + } + } + + if (errno == 0) { + /* TODO: if error isn't found, add it dynamically */ + printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__, + errstr); + errno = 1; + } + + return -errno; +} diff --git a/fs/9p/error.h b/fs/9p/error.h new file mode 100644 index 0000000000000..4bf2cf5aa1bb6 --- /dev/null +++ b/fs/9p/error.h @@ -0,0 +1,181 @@ +/* + * linux/fs/9p/error.h + * + * Huge Nasty Error Table + * + * Plan 9 uses error strings, Unix uses error numbers. This table tries to + * match UNIX strings and Plan 9 strings to unix error numbers. It is used + * to preload the dynamic error table which can also track user-specific error + * strings. + * + * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> + * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/errno.h> + +struct errormap { + char *name; + int val; + + struct hlist_node list; +}; + +#define ERRHASHSZ 32 +static struct hlist_head hash_errmap[ERRHASHSZ]; + +/* FixMe - reduce to a reasonable size */ +static struct errormap errmap[] = { + {"Operation not permitted", 1}, + {"wstat prohibited", 1}, + {"No such file or directory", 2}, + {"file not found", 2}, + {"Interrupted system call", 4}, + {"Input/output error", 5}, + {"No such device or address", 6}, + {"Argument list too long", 7}, + {"Bad file descriptor", 9}, + {"Resource temporarily unavailable", 11}, + {"Cannot allocate memory", 12}, + {"Permission denied", 13}, + {"Bad address", 14}, + {"Block device required", 15}, + {"Device or resource busy", 16}, + {"File exists", 17}, + {"Invalid cross-device link", 18}, + {"No such device", 19}, + {"Not a directory", 20}, + {"Is a directory", 21}, + {"Invalid argument", 22}, + {"Too many open files in system", 23}, + {"Too many open files", 24}, + {"Text file busy", 26}, + {"File too large", 27}, + {"No space left on device", 28}, + {"Illegal seek", 29}, + {"Read-only file system", 30}, + {"Too many links", 31}, + {"Broken pipe", 32}, + {"Numerical argument out of domain", 33}, + {"Numerical result out of range", 34}, + {"Resource deadlock avoided", 35}, + {"File name too long", 36}, + {"No locks available", 37}, + {"Function not implemented", 38}, + {"Directory not empty", 39}, + {"Too many levels of symbolic links", 40}, + {"Unknown error 41", 41}, + {"No message of desired type", 42}, + {"Identifier removed", 43}, + {"File locking deadlock error", 58}, + {"No data available", 61}, + {"Machine is not on the network", 64}, + {"Package not installed", 65}, + {"Object is remote", 66}, + {"Link has been severed", 67}, + {"Communication error on send", 70}, + {"Protocol error", 71}, + {"Bad message", 74}, + {"File descriptor in bad state", 77}, + {"Streams pipe error", 86}, + {"Too many users", 87}, + {"Socket operation on non-socket", 88}, + {"Message too long", 90}, + {"Protocol not available", 92}, + {"Protocol not supported", 93}, + {"Socket type not supported", 94}, + {"Operation not supported", 95}, + {"Protocol family not supported", 96}, + {"Network is down", 100}, + {"Network is unreachable", 101}, + {"Network dropped connection on reset", 102}, + {"Software caused connection abort", 103}, + {"Connection reset by peer", 104}, + {"No buffer space available", 105}, + {"Transport endpoint is already connected", 106}, + {"Transport endpoint is not connected", 107}, + {"Cannot send after transport endpoint shutdown", 108}, + {"Connection timed out", 110}, + {"Connection refused", 111}, + {"Host is down", 112}, + {"No route to host", 113}, + {"Operation already in progress", 114}, + {"Operation now in progress", 115}, + {"Is a named type file", 120}, + {"Remote I/O error", 121}, + {"Disk quota exceeded", 122}, + {"Operation canceled", 125}, + {"Unknown error 126", 126}, + {"Unknown error 127", 127}, +/* errors from fossil, vacfs, and u9fs */ + {"fid unknown or out of range", EBADF}, + {"permission denied", EACCES}, + {"file does not exist", ENOENT}, + {"authentication failed", ECONNREFUSED}, + {"bad offset in directory read", ESPIPE}, + {"bad use of fid", EBADF}, + {"wstat can't convert between files and directories", EPERM}, + {"directory is not empty", ENOTEMPTY}, + {"file exists", EEXIST}, + {"file already exists", EEXIST}, + {"file or directory already exists", EEXIST}, + {"fid already in use", EBADF}, + {"file in use", ETXTBSY}, + {"i/o error", EIO}, + {"file already open for I/O", ETXTBSY}, + {"illegal mode", EINVAL}, + {"illegal name", ENAMETOOLONG}, + {"not a directory", ENOTDIR}, + {"not a member of proposed group", EINVAL}, + {"not owner", EACCES}, + {"only owner can change group in wstat", EACCES}, + {"read only file system", EROFS}, + {"no access to special file", EPERM}, + {"i/o count too large", EIO}, + {"unknown group", EINVAL}, + {"unknown user", EINVAL}, + {"bogus wstat buffer", EPROTO}, + {"exclusive use file already open", EAGAIN}, + {"corrupted directory entry", EIO}, + {"corrupted file entry", EIO}, + {"corrupted block label", EIO}, + {"corrupted meta data", EIO}, + {"illegal offset", EINVAL}, + {"illegal path element", ENOENT}, + {"root of file system is corrupted", EIO}, + {"corrupted super block", EIO}, + {"protocol botch", EPROTO}, + {"file system is full", ENOSPC}, + {"file is in use", EAGAIN}, + {"directory entry is not allocated", ENOENT}, + {"file is read only", EROFS}, + {"file has been removed", EIDRM}, + {"only support truncation to zero length", EPERM}, + {"cannot remove root", EPERM}, + {"file too big", EFBIG}, + {"venti i/o error", EIO}, + /* these are not errors */ + {"u9fs rhostsauth: no authentication required", 0}, + {"u9fs authnone: no authentication required", 0}, + {NULL, -1} +}; + +extern int v9fs_error_init(void); +extern int v9fs_errstr2errno(char *errstr); diff --git a/fs/9p/fid.c b/fs/9p/fid.c new file mode 100644 index 0000000000000..821c9c4d76aa0 --- /dev/null +++ b/fs/9p/fid.c @@ -0,0 +1,241 @@ +/* + * V9FS FID Management + * + * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/idr.h> + +#include "debug.h" +#include "v9fs.h" +#include "9p.h" +#include "v9fs_vfs.h" +#include "transport.h" +#include "mux.h" +#include "conv.h" +#include "fid.h" + +/** + * v9fs_fid_insert - add a fid to a dentry + * @fid: fid to add + * @dentry: dentry that it is being added to + * + */ + +static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) +{ + struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; + dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid, + dentry->d_iname, dentry); + if (dentry->d_fsdata == NULL) { + dentry->d_fsdata = + kmalloc(sizeof(struct list_head), GFP_KERNEL); + if (dentry->d_fsdata == NULL) { + dprintk(DEBUG_ERROR, "Out of memory\n"); + return -ENOMEM; + } + fid_list = (struct list_head *)dentry->d_fsdata; + INIT_LIST_HEAD(fid_list); /* Initialize list head */ + } + + fid->uid = current->uid; + fid->pid = current->pid; + list_add(&fid->list, fid_list); + return 0; +} + +/** + * v9fs_fid_create - allocate a FID structure + * @dentry - dentry to link newly created fid to + * + */ + +struct v9fs_fid *v9fs_fid_create(struct dentry *dentry) +{ + struct v9fs_fid *new; + + new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); + if (new == NULL) { + dprintk(DEBUG_ERROR, "Out of Memory\n"); + return ERR_PTR(-ENOMEM); + } + + new->fid = -1; + new->fidopen = 0; + new->fidcreate = 0; + new->fidclunked = 0; + new->iounit = 0; + + if (v9fs_fid_insert(new, dentry) == 0) + return new; + else { + dprintk(DEBUG_ERROR, "Problems inserting to dentry\n"); + kfree(new); + return NULL; + } +} + +/** + * v9fs_fid_destroy - deallocate a FID structure + * @fid: fid to destroy + * + */ + +void v9fs_fid_destroy(struct v9fs_fid *fid) +{ + list_del(&fid->list); + kfree(fid); +} + +/** + * v9fs_fid_lookup - retrieve the right fid from a particular dentry + * @dentry: dentry to look for fid in + * @type: intent of lookup (operation or traversal) + * + * search list of fids associated with a dentry for a fid with a matching + * thread id or uid. If that fails, look up the dentry's parents to see if you + * can find a matching fid. + * + */ + +struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type) +{ + struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; + struct v9fs_fid *current_fid = NULL; + struct v9fs_fid *temp = NULL; + struct v9fs_fid *return_fid = NULL; + int found_parent = 0; + int found_user = 0; + + dprintk(DEBUG_9P, " dentry: %s (%p) type %d\n", dentry->d_iname, dentry, + type); + + if (fid_list && !list_empty(fid_list)) { + list_for_each_entry_safe(current_fid, temp, fid_list, list) { + if (current_fid->uid == current->uid) { + if (return_fid == NULL) { + if ((type == FID_OP) + || (!current_fid->fidopen)) { + return_fid = current_fid; + found_user = 1; + } + } + } + if (current_fid->pid == current->real_parent->pid) { + if ((return_fid == NULL) || (found_parent) + || (found_user)) { + if ((type == FID_OP) + || (!current_fid->fidopen)) { + return_fid = current_fid; + found_parent = 1; + found_user = 0; + } + } + } + if (current_fid->pid == current->pid) { + if ((type == FID_OP) || + (!current_fid->fidopen)) { + return_fid = current_fid; + found_parent = 0; + found_user = 0; + } + } + } + } + + /* we are at the root but didn't match */ + if ((!return_fid) && (dentry->d_parent == dentry)) { + /* TODO: clone attach with new uid */ + return_fid = current_fid; + } + + if (!return_fid) { + struct dentry *par = current->fs->pwd->d_parent; + int count = 1; + while (par != NULL) { + if (par == dentry) + break; + count++; + if (par == par->d_parent) { + dprintk(DEBUG_ERROR, + "got to root without finding dentry\n"); + break; + } + par = par->d_parent; + } + +/* XXX - there may be some duplication we can get rid of */ + if (par == dentry) { + /* we need to fid_lookup the starting point */ + int fidnum = -1; + int oldfid = -1; + int result = -1; + struct v9fs_session_info *v9ses = + v9fs_inode2v9ses(current->fs->pwd->d_inode); + + current_fid = + v9fs_fid_lookup(current->fs->pwd, FID_WALK); + if (current_fid == NULL) { + dprintk(DEBUG_ERROR, + "process cwd doesn't have a fid\n"); + return return_fid; + } + oldfid = current_fid->fid; + par = current->fs->pwd; + /* TODO: take advantage of multiwalk */ + + fidnum = v9fs_get_idpool(&v9ses->fidpool); + if (fidnum < 0) { + dprintk(DEBUG_ERROR, + "could not get a new fid num\n"); + return return_fid; + } + + while (par != dentry) { + result = + v9fs_t_walk(v9ses, oldfid, fidnum, "..", + NULL); + if (result < 0) { + dprintk(DEBUG_ERROR, + "problem walking to parent\n"); + + break; + } + oldfid = fidnum; + if (par == par->d_parent) { + dprintk(DEBUG_ERROR, + "can't find dentry\n"); + break; + } + par = par->d_parent; + } + if (par == dentry) { + return_fid = v9fs_fid_create(dentry); + return_fid->fid = fidnum; + } + } + } + + return return_fid; +} diff --git a/fs/9p/fid.h b/fs/9p/fid.h new file mode 100644 index 0000000000000..7db478ccca365 --- /dev/null +++ b/fs/9p/fid.h @@ -0,0 +1,57 @@ +/* + * V9FS FID Management + * + * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com> + * + * 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: + * Free Software Foundation + * 51 Franklin Street, Fifth Floor + * Boston, MA 02111-1301 USA + * + */ + +#include <linux/list.h> + +#define FID_OP 0 +#define FID_WALK 1 + +struct v9fs_fid { + struct list_head list; /* list of fids associated with a dentry */ + struct list_head active; /* XXX - debug */ + + u32 fid; + unsigned char fidopen; /* set when fid is opened */ + unsigned char fidcreate; /* set when fid was just created */ + unsigned char fidclunked; /* set when fid has already been clunked */ + + struct v9fs_qid qid; + u32 iounit; + + /* readdir stuff */ + int rdir_fpos; + loff_t rdir_pos; + struct v9fs_fcall *rdir_fcall; + + /* management stuff */ + pid_t pid; /* thread associated with this fid */ + uid_t uid; /* user associated with this fid */ + + /* private data */ + struct file *filp; /* backpointer to File struct for open files */ + struct v9fs_session_info *v9ses; /* session info for this FID */ +}; + +struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type); +void v9fs_fid_destroy(struct v9fs_fid *fid); +struct v9fs_fid *v9fs_fid_create(struct dentry *); -- GitLab From 1346f51ede71fc1e5021062898d150e192dc4dc8 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:25 -0700 Subject: [PATCH 215/563] [PATCH] v9fs: Change error magic numbers to defined constants Change magic error numbers to system defined constants in v9fs error.h As suggested by Jan-Benedict Glaw. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/error.h | 158 ++++++++++++++++++++++++-------------------------- 1 file changed, 77 insertions(+), 81 deletions(-) diff --git a/fs/9p/error.h b/fs/9p/error.h index 4bf2cf5aa1bb6..6dbb66f5b28fa 100644 --- a/fs/9p/error.h +++ b/fs/9p/error.h @@ -30,6 +30,7 @@ */ #include <linux/errno.h> +#include <asm/errno.h> struct errormap { char *name; @@ -43,87 +44,82 @@ static struct hlist_head hash_errmap[ERRHASHSZ]; /* FixMe - reduce to a reasonable size */ static struct errormap errmap[] = { - {"Operation not permitted", 1}, - {"wstat prohibited", 1}, - {"No such file or directory", 2}, - {"file not found", 2}, - {"Interrupted system call", 4}, - {"Input/output error", 5}, - {"No such device or address", 6}, - {"Argument list too long", 7}, - {"Bad file descriptor", 9}, - {"Resource temporarily unavailable", 11}, - {"Cannot allocate memory", 12}, - {"Permission denied", 13}, - {"Bad address", 14}, - {"Block device required", 15}, - {"Device or resource busy", 16}, - {"File exists", 17}, - {"Invalid cross-device link", 18}, - {"No such device", 19}, - {"Not a directory", 20}, - {"Is a directory", 21}, - {"Invalid argument", 22}, - {"Too many open files in system", 23}, - {"Too many open files", 24}, - {"Text file busy", 26}, - {"File too large", 27}, - {"No space left on device", 28}, - {"Illegal seek", 29}, - {"Read-only file system", 30}, - {"Too many links", 31}, - {"Broken pipe", 32}, - {"Numerical argument out of domain", 33}, - {"Numerical result out of range", 34}, - {"Resource deadlock avoided", 35}, - {"File name too long", 36}, - {"No locks available", 37}, - {"Function not implemented", 38}, - {"Directory not empty", 39}, - {"Too many levels of symbolic links", 40}, - {"Unknown error 41", 41}, - {"No message of desired type", 42}, - {"Identifier removed", 43}, - {"File locking deadlock error", 58}, - {"No data available", 61}, - {"Machine is not on the network", 64}, - {"Package not installed", 65}, - {"Object is remote", 66}, - {"Link has been severed", 67}, - {"Communication error on send", 70}, - {"Protocol error", 71}, - {"Bad message", 74}, - {"File descriptor in bad state", 77}, - {"Streams pipe error", 86}, - {"Too many users", 87}, - {"Socket operation on non-socket", 88}, - {"Message too long", 90}, - {"Protocol not available", 92}, - {"Protocol not supported", 93}, - {"Socket type not supported", 94}, - {"Operation not supported", 95}, - {"Protocol family not supported", 96}, - {"Network is down", 100}, - {"Network is unreachable", 101}, - {"Network dropped connection on reset", 102}, - {"Software caused connection abort", 103}, - {"Connection reset by peer", 104}, - {"No buffer space available", 105}, - {"Transport endpoint is already connected", 106}, - {"Transport endpoint is not connected", 107}, - {"Cannot send after transport endpoint shutdown", 108}, - {"Connection timed out", 110}, - {"Connection refused", 111}, - {"Host is down", 112}, - {"No route to host", 113}, - {"Operation already in progress", 114}, - {"Operation now in progress", 115}, - {"Is a named type file", 120}, - {"Remote I/O error", 121}, - {"Disk quota exceeded", 122}, - {"Operation canceled", 125}, - {"Unknown error 126", 126}, - {"Unknown error 127", 127}, + {"Operation not permitted", EPERM}, + {"wstat prohibited", EPERM}, + {"No such file or directory", ENOENT}, + {"file not found", ENOENT}, + {"Interrupted system call", EINTR}, + {"Input/output error", EIO}, + {"No such device or address", ENXIO}, + {"Argument list too long", E2BIG}, + {"Bad file descriptor", EBADF}, + {"Resource temporarily unavailable", EAGAIN}, + {"Cannot allocate memory", ENOMEM}, + {"Permission denied", EACCES}, + {"Bad address", EFAULT}, + {"Block device required", ENOTBLK}, + {"Device or resource busy", EBUSY}, + {"File exists", EEXIST}, + {"Invalid cross-device link", EXDEV}, + {"No such device", ENODEV}, + {"Not a directory", ENOTDIR}, + {"Is a directory", EISDIR}, + {"Invalid argument", EINVAL}, + {"Too many open files in system", ENFILE}, + {"Too many open files", EMFILE}, + {"Text file busy", ETXTBSY}, + {"File too large", EFBIG}, + {"No space left on device", ENOSPC}, + {"Illegal seek", ESPIPE}, + {"Read-only file system", EROFS}, + {"Too many links", EMLINK}, + {"Broken pipe", EPIPE}, + {"Numerical argument out of domain", EDOM}, + {"Numerical result out of range", ERANGE}, + {"Resource deadlock avoided", EDEADLK}, + {"File name too long", ENAMETOOLONG}, + {"No locks available", ENOLCK}, + {"Function not implemented", ENOSYS}, + {"Directory not empty", ENOTEMPTY}, + {"Too many levels of symbolic links", ELOOP}, + {"No message of desired type", ENOMSG}, + {"Identifier removed", EIDRM}, + {"No data available", ENODATA}, + {"Machine is not on the network", ENONET}, + {"Package not installed", ENOPKG}, + {"Object is remote", EREMOTE}, + {"Link has been severed", ENOLINK}, + {"Communication error on send", ECOMM}, + {"Protocol error", EPROTO}, + {"Bad message", EBADMSG}, + {"File descriptor in bad state", EBADFD}, + {"Streams pipe error", ESTRPIPE}, + {"Too many users", EUSERS}, + {"Socket operation on non-socket", ENOTSOCK}, + {"Message too long", EMSGSIZE}, + {"Protocol not available", ENOPROTOOPT}, + {"Protocol not supported", EPROTONOSUPPORT}, + {"Socket type not supported", ESOCKTNOSUPPORT}, + {"Operation not supported", EOPNOTSUPP}, + {"Protocol family not supported", EPFNOSUPPORT}, + {"Network is down", ENETDOWN}, + {"Network is unreachable", ENETUNREACH}, + {"Network dropped connection on reset", ENETRESET}, + {"Software caused connection abort", ECONNABORTED}, + {"Connection reset by peer", ECONNRESET}, + {"No buffer space available", ENOBUFS}, + {"Transport endpoint is already connected", EISCONN}, + {"Transport endpoint is not connected", ENOTCONN}, + {"Cannot send after transport endpoint shutdown", ESHUTDOWN}, + {"Connection timed out", ETIMEDOUT}, + {"Connection refused", ECONNREFUSED}, + {"Host is down", EHOSTDOWN}, + {"No route to host", EHOSTUNREACH}, + {"Operation already in progress", EALREADY}, + {"Operation now in progress", EINPROGRESS}, + {"Is a named type file", EISNAM}, + {"Remote I/O error", EREMOTEIO}, + {"Disk quota exceeded", EDQUOT}, /* errors from fossil, vacfs, and u9fs */ {"fid unknown or out of range", EBADF}, {"permission denied", EACCES}, -- GitLab From 73c592b9b844cc353bbaea690fb4aa652ac168a6 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:26 -0700 Subject: [PATCH 216/563] [PATCH] v9fs: Clean-up vfs_inode and setattr functions Cleanup code in v9fs vfs_inode as suggested by Alexey Dobriyan. Did some major revamping of the v9fs setattr code to remove unnecessary allocations and clean up some dead-code. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/error.h | 2 +- fs/9p/vfs_inode.c | 131 +++++++++++++--------------------------------- 2 files changed, 36 insertions(+), 97 deletions(-) diff --git a/fs/9p/error.h b/fs/9p/error.h index 6dbb66f5b28fa..2eb5927d589ed 100644 --- a/fs/9p/error.h +++ b/fs/9p/error.h @@ -139,7 +139,7 @@ static struct errormap errmap[] = { {"illegal mode", EINVAL}, {"illegal name", ENAMETOOLONG}, {"not a directory", ENOTDIR}, - {"not a member of proposed group", EINVAL}, + {"not a member of proposed group", EPERM}, {"not owner", EACCES}, {"only owner can change group in wstat", EACCES}, {"read only file system", EROFS}, diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index ef78af7ef04ba..6d2357d1dacd7 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1,7 +1,7 @@ /* * linux/fs/9p/vfs_inode.c * - * This file contians vfs inode ops for the 9P2000 protocol. + * This file contains vfs inode ops for the 9P2000 protocol. * * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> @@ -54,7 +54,7 @@ static struct inode_operations v9fs_symlink_inode_operations; * */ -static inline int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) +static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) { int res; res = mode & 0777; @@ -92,7 +92,7 @@ static inline int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) * */ -static inline int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) +static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) { int res; @@ -132,7 +132,7 @@ static inline int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) * */ -static inline void +static void v9fs_blank_mistat(struct v9fs_session_info *v9ses, struct v9fs_stat *mistat) { mistat->type = ~0; @@ -160,7 +160,7 @@ v9fs_blank_mistat(struct v9fs_session_info *v9ses, struct v9fs_stat *mistat) /** * v9fs_mistat2unix - convert mistat to unix stat * @mistat: Plan 9 metadata (mistat) structure - * @stat: unix metadata (stat) structure to populate + * @buf: unix metadata (stat) structure to populate * @sb: superblock * */ @@ -177,22 +177,11 @@ v9fs_mistat2unix(struct v9fs_stat *mistat, struct stat *buf, buf->st_mtime = mistat->mtime; buf->st_ctime = mistat->mtime; - if (v9ses && v9ses->extended) { - /* TODO: string to uid mapping via user-space daemon */ - buf->st_uid = mistat->n_uid; - buf->st_gid = mistat->n_gid; - - sscanf(mistat->uid, "%x", (unsigned int *)&buf->st_uid); - sscanf(mistat->gid, "%x", (unsigned int *)&buf->st_gid); - } else { - buf->st_uid = v9ses->uid; - buf->st_gid = v9ses->gid; - } - buf->st_uid = (unsigned short)-1; buf->st_gid = (unsigned short)-1; if (v9ses && v9ses->extended) { + /* TODO: string to uid mapping via user-space daemon */ if (mistat->n_uid != -1) sscanf(mistat->uid, "%x", (unsigned int *)&buf->st_uid); @@ -290,7 +279,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) * @dir: directory inode file is being created in * @file_dentry: dentry file is being created in * @perm: permissions file is being created with - * @open_mode: resulting open mode for file ??? + * @open_mode: resulting open mode for file * */ @@ -434,9 +423,9 @@ v9fs_create(struct inode *dir, /** * v9fs_remove - helper function to remove files and directories - * @inode: directory inode that is being deleted - * @dentry: dentry that is being deleted - * @rmdir: where we are a file or a directory + * @dir: directory inode that is being deleted + * @file: dentry that is being deleted + * @rmdir: removing a directory * */ @@ -502,7 +491,7 @@ v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm, /** * v9fs_vfs_mkdir - VFS mkdir hook to create a directory - * @i: inode that is being unlinked + * @inode: inode that is being unlinked * @dentry: dentry that is being unlinked * @mode: mode for new directory * @@ -624,7 +613,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, /** * v9fs_vfs_unlink - VFS unlink hook to delete an inode * @i: inode that is being unlinked - * @dentry: dentry that is being unlinked + * @d: dentry that is being unlinked * */ @@ -636,7 +625,7 @@ static int v9fs_vfs_unlink(struct inode *i, struct dentry *d) /** * v9fs_vfs_rmdir - VFS unlink hook to delete a directory * @i: inode that is being unlinked - * @dentry: dentry that is being unlinked + * @d: dentry that is being unlinked * */ @@ -674,6 +663,9 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, dprintk(DEBUG_VFS, "\n"); + if (!mistat) + return -ENOMEM; + if ((!oldfid) || (!olddirfid) || (!newdirfid)) { dprintk(DEBUG_ERROR, "problem with arguments\n"); return -EBADF; @@ -771,20 +763,21 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) { struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP); - struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); struct v9fs_fcall *fcall = NULL; + struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); int res = -EPERM; dprintk(DEBUG_VFS, "\n"); + + if (!mistat) + return -ENOMEM; + if (!fid) { dprintk(DEBUG_ERROR, "Couldn't find fid associated with dentry\n"); return -EBADF; } - if (!mistat) - return -ENOMEM; - v9fs_blank_mistat(v9ses, mistat); if (iattr->ia_valid & ATTR_MODE) mistat->mode = unixmode2p9mode(v9ses, iattr->ia_mode); @@ -799,72 +792,19 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) mistat->length = iattr->ia_size; if (v9ses->extended) { - char *uid = kmalloc(strlen(mistat->uid), GFP_KERNEL); - char *gid = kmalloc(strlen(mistat->gid), GFP_KERNEL); - char *muid = kmalloc(strlen(mistat->muid), GFP_KERNEL); - char *name = kmalloc(strlen(mistat->name), GFP_KERNEL); - char *extension = kmalloc(strlen(mistat->extension), - GFP_KERNEL); - - if ((!uid) || (!gid) || (!muid) || (!name) || (!extension)) { - kfree(uid); - kfree(gid); - kfree(muid); - kfree(name); - kfree(extension); - - return -ENOMEM; - } - - strcpy(uid, mistat->uid); - strcpy(gid, mistat->gid); - strcpy(muid, mistat->muid); - strcpy(name, mistat->name); - strcpy(extension, mistat->extension); + char *ptr = mistat->data+1; if (iattr->ia_valid & ATTR_UID) { - if (strlen(uid) != 8) { - dprintk(DEBUG_ERROR, "uid strlen is %u not 8\n", - (unsigned int)strlen(uid)); - sprintf(uid, "%08x", iattr->ia_uid); - } else { - kfree(uid); - uid = kmalloc(9, GFP_KERNEL); - } - - sprintf(uid, "%08x", iattr->ia_uid); + mistat->uid = ptr; + ptr += 1+sprintf(ptr, "%08x", iattr->ia_uid); mistat->n_uid = iattr->ia_uid; } if (iattr->ia_valid & ATTR_GID) { - if (strlen(gid) != 8) - dprintk(DEBUG_ERROR, "gid strlen is %u not 8\n", - (unsigned int)strlen(gid)); - else { - kfree(gid); - gid = kmalloc(9, GFP_KERNEL); - } - - sprintf(gid, "%08x", iattr->ia_gid); + mistat->gid = ptr; + ptr += 1+sprintf(ptr, "%08x", iattr->ia_gid); mistat->n_gid = iattr->ia_gid; } - - mistat->uid = mistat->data; - strcpy(mistat->uid, uid); - mistat->gid = mistat->data + strlen(uid) + 1; - strcpy(mistat->gid, gid); - mistat->muid = mistat->gid + strlen(gid) + 1; - strcpy(mistat->muid, muid); - mistat->name = mistat->muid + strlen(muid) + 1; - strcpy(mistat->name, name); - mistat->extension = mistat->name + strlen(name) + 1; - strcpy(mistat->extension, extension); - - kfree(uid); - kfree(gid); - kfree(muid); - kfree(name); - kfree(extension); } res = v9fs_t_wstat(v9ses, fid->fid, mistat, &fcall); @@ -985,17 +925,14 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) int retval = -EPERM; struct v9fs_fid *newfid; struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); - struct super_block *sb = dir ? dir->i_sb : NULL; struct v9fs_fcall *fcall = NULL; struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, symname); - if ((!dentry) || (!sb) || (!v9ses)) { - dprintk(DEBUG_ERROR, "problem with arguments\n"); - return -EBADF; - } + if (!mistat) + return -ENOMEM; if (!v9ses->extended) { dprintk(DEBUG_ERROR, "not extended\n"); @@ -1040,7 +977,7 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) /** * v9fs_readlink - read a symlink's location (internal version) * @dentry: dentry for symlink - * @buf: buffer to load symlink location into + * @buffer: buffer to load symlink location into * @buflen: length of buffer * */ @@ -1179,7 +1116,7 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void * v9fs_vfs_link - create a hardlink * @old_dentry: dentry for file to link to * @dir: inode destination for new link - * @new_dentry: dentry for link + * @dentry: dentry for link * */ @@ -1274,6 +1211,9 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); + if (!mistat) + return -ENOMEM; + if (!new_valid_dev(rdev)) { retval = -EINVAL; goto FreeMem; @@ -1302,7 +1242,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) sprintf(symname, "b %u %u", MAJOR(rdev), MINOR(rdev)); else if (S_ISCHR(mode)) sprintf(symname, "c %u %u", MAJOR(rdev), MINOR(rdev)); - else if (S_ISFIFO(mode)) ; /* DO NOTHING */ + else if (S_ISFIFO(mode)) + ; /* DO NOTHING */ else { retval = -EINVAL; goto FreeMem; @@ -1319,8 +1260,6 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) FCALL_ERROR(fcall)); goto FreeMem; } - - kfree(fcall); } /* need to update dcache so we show up */ -- GitLab From 5d58bec5b7a8b8303df0a4dcb9a18feeefac6091 Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:27 -0700 Subject: [PATCH 217/563] [PATCH] v9fs: Fix support for special files (devices, named pipes, etc.) Fix v9fs special files (block, char devices) support. Signed-off-by: Latchesar Ionkov <lucho@ionkov.net> Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/vfs_inode.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 6d2357d1dacd7..36fff087167f9 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -250,6 +250,9 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) case S_IFBLK: case S_IFCHR: case S_IFSOCK: + init_special_inode(inode, inode->i_mode, + inode->i_rdev); + break; case S_IFREG: inode->i_op = &v9fs_file_inode_operations; inode->i_fop = &v9fs_file_operations; -- GitLab From b501611a6f78558eafcf09b228abd866d4ea5d9f Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:27 -0700 Subject: [PATCH 218/563] [PATCH] v9fs: readlink extended mode check LANL reported some issues with random crashes during mount of legacy protocol servers (9P2000 versus 9P2000.u) -- crash was always happening in readlink (which should never happen in legacy mode). Added some sanity conditionals to the get_inode code which should prevent the errors LANL was seeing. Code tested benign through regression. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/vfs_inode.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 36fff087167f9..0c13fc600049d 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -44,6 +44,7 @@ #include "fid.h" static struct inode_operations v9fs_dir_inode_operations; +static struct inode_operations v9fs_dir_inode_operations_ext; static struct inode_operations v9fs_file_inode_operations; static struct inode_operations v9fs_symlink_inode_operations; @@ -232,6 +233,7 @@ v9fs_mistat2unix(struct v9fs_stat *mistat, struct stat *buf, struct inode *v9fs_get_inode(struct super_block *sb, int mode) { struct inode *inode = NULL; + struct v9fs_session_info *v9ses = sb->s_fs_info; dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); @@ -250,6 +252,10 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) case S_IFBLK: case S_IFCHR: case S_IFSOCK: + if(!v9ses->extended) { + dprintk(DEBUG_ERROR, "special files without extended mode\n"); + return ERR_PTR(-EINVAL); + } init_special_inode(inode, inode->i_mode, inode->i_rdev); break; @@ -257,14 +263,21 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) inode->i_op = &v9fs_file_inode_operations; inode->i_fop = &v9fs_file_operations; break; + case S_IFLNK: + if(!v9ses->extended) { + dprintk(DEBUG_ERROR, "extended modes used w/o 9P2000.u\n"); + return ERR_PTR(-EINVAL); + } + inode->i_op = &v9fs_symlink_inode_operations; + break; case S_IFDIR: inode->i_nlink++; - inode->i_op = &v9fs_dir_inode_operations; + if(v9ses->extended) + inode->i_op = &v9fs_dir_inode_operations_ext; + else + inode->i_op = &v9fs_dir_inode_operations; inode->i_fop = &v9fs_dir_operations; break; - case S_IFLNK: - inode->i_op = &v9fs_symlink_inode_operations; - break; default: dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", mode, mode & S_IFMT); @@ -1284,7 +1297,7 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) return retval; } -static struct inode_operations v9fs_dir_inode_operations = { +static struct inode_operations v9fs_dir_inode_operations_ext = { .create = v9fs_vfs_create, .lookup = v9fs_vfs_lookup, .symlink = v9fs_vfs_symlink, @@ -1299,6 +1312,18 @@ static struct inode_operations v9fs_dir_inode_operations = { .setattr = v9fs_vfs_setattr, }; +static struct inode_operations v9fs_dir_inode_operations = { + .create = v9fs_vfs_create, + .lookup = v9fs_vfs_lookup, + .unlink = v9fs_vfs_unlink, + .mkdir = v9fs_vfs_mkdir, + .rmdir = v9fs_vfs_rmdir, + .mknod = v9fs_vfs_mknod, + .rename = v9fs_vfs_rename, + .getattr = v9fs_vfs_getattr, + .setattr = v9fs_vfs_setattr, +}; + static struct inode_operations v9fs_file_inode_operations = { .getattr = v9fs_vfs_getattr, .setattr = v9fs_vfs_setattr, -- GitLab From cb2e87a65d6cd735eb06fa595bf90497af28c37b Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen <ericvh@gmail.com> Date: Fri, 9 Sep 2005 13:04:28 -0700 Subject: [PATCH 219/563] [PATCH] v9fs: fix handling of malformed 9P messages This patch attempts to do a better job of cleaning up after detecting errors on the transport. This should also improve error reporting on broken connections to servers. Signed-off-by: Latchesar Ionkov <lucho@ionkov.net> Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/9p/error.h | 1 + fs/9p/mux.c | 53 +++++++++++++++++++++++++++++----------------- fs/9p/mux.h | 1 + fs/9p/trans_sock.c | 12 +++++++++-- 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/fs/9p/error.h b/fs/9p/error.h index 2eb5927d589ed..78f89acf7c9af 100644 --- a/fs/9p/error.h +++ b/fs/9p/error.h @@ -47,6 +47,7 @@ static struct errormap errmap[] = { {"Operation not permitted", EPERM}, {"wstat prohibited", EPERM}, {"No such file or directory", ENOENT}, + {"directory entry not found", ENOENT}, {"file not found", ENOENT}, {"Interrupted system call", EINTR}, {"Input/output error", EIO}, diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 0854bef58c166..8835b576f7445 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -162,18 +162,21 @@ static int v9fs_recv(struct v9fs_session_info *v9ses, struct v9fs_rpcreq *req) dprintk(DEBUG_MUX, "waiting for response: %d\n", req->tcall->tag); ret = wait_event_interruptible(v9ses->read_wait, ((v9ses->transport->status != Connected) || - (req->rcall != 0) || dprintcond(v9ses, req))); + (req->rcall != 0) || (req->err < 0) || + dprintcond(v9ses, req))); dprintk(DEBUG_MUX, "got it: rcall %p\n", req->rcall); + + spin_lock(&v9ses->muxlock); + list_del(&req->next); + spin_unlock(&v9ses->muxlock); + + if (req->err < 0) + return req->err; + if (v9ses->transport->status == Disconnected) return -ECONNRESET; - if (ret == 0) { - spin_lock(&v9ses->muxlock); - list_del(&req->next); - spin_unlock(&v9ses->muxlock); - } - return ret; } @@ -245,6 +248,9 @@ v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall, if (!v9ses) return -EINVAL; + if (!v9ses->transport || v9ses->transport->status != Connected) + return -EIO; + if (rcall) *rcall = NULL; @@ -257,6 +263,7 @@ v9fs_mux_rpc(struct v9fs_session_info *v9ses, struct v9fs_fcall *tcall, tcall->tag = tid; req.tcall = tcall; + req.err = 0; req.rcall = NULL; ret = v9fs_send(v9ses, &req); @@ -371,16 +378,21 @@ static int v9fs_recvproc(void *data) } err = read_message(v9ses, rcall, v9ses->maxdata + V9FS_IOHDRSZ); - if (err < 0) { - kfree(rcall); - break; - } spin_lock(&v9ses->muxlock); - list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { - if (rreq->tcall->tag == rcall->tag) { - req = rreq; - req->rcall = rcall; - break; + if (err < 0) { + list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { + rreq->err = err; + } + if(err != -ERESTARTSYS) + eprintk(KERN_ERR, + "Transport error while reading message %d\n", err); + } else { + list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { + if (rreq->tcall->tag == rcall->tag) { + req = rreq; + req->rcall = rcall; + break; + } } } @@ -399,9 +411,10 @@ static int v9fs_recvproc(void *data) spin_unlock(&v9ses->muxlock); if (!req) { - dprintk(DEBUG_ERROR, - "unexpected response: id %d tag %d\n", - rcall->id, rcall->tag); + if (err >= 0) + dprintk(DEBUG_ERROR, + "unexpected response: id %d tag %d\n", + rcall->id, rcall->tag); kfree(rcall); } @@ -410,6 +423,8 @@ static int v9fs_recvproc(void *data) set_current_state(TASK_INTERRUPTIBLE); } + v9ses->transport->close(v9ses->transport); + /* Inform all pending processes about the failure */ wake_up_all(&v9ses->read_wait); diff --git a/fs/9p/mux.h b/fs/9p/mux.h index 82ce793af1b57..4994cb10badfe 100644 --- a/fs/9p/mux.h +++ b/fs/9p/mux.h @@ -28,6 +28,7 @@ struct v9fs_rpcreq { struct v9fs_fcall *tcall; struct v9fs_fcall *rcall; + int err; /* error code if response failed */ /* XXX - could we put scatter/gather buffers here? */ diff --git a/fs/9p/trans_sock.c b/fs/9p/trans_sock.c index 081d1c8478030..01e26f0013ace 100644 --- a/fs/9p/trans_sock.c +++ b/fs/9p/trans_sock.c @@ -254,7 +254,12 @@ v9fs_unix_init(struct v9fs_session_info *v9ses, const char *dev_name, static void v9fs_sock_close(struct v9fs_transport *trans) { - struct v9fs_trans_sock *ts = trans ? trans->priv : NULL; + struct v9fs_trans_sock *ts; + + if (!trans) + return; + + ts = trans->priv; if ((ts) && (ts->s)) { dprintk(DEBUG_TRANS, "closing the socket %p\n", ts->s); @@ -264,7 +269,10 @@ static void v9fs_sock_close(struct v9fs_transport *trans) dprintk(DEBUG_TRANS, "socket closed\n"); } - kfree(ts); + if (ts) + kfree(ts); + + trans->priv = NULL; } struct v9fs_transport v9fs_trans_tcp = { -- GitLab From 7726e9e10fc6e026ed2dc00e48f4a3ffc1254ad2 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:04:29 -0700 Subject: [PATCH 220/563] [PATCH] fbdev: Add fbset -a support Add capability to fbdev to listen to the FB_ACTIVATE_ALL flag. If set, it notifies fbcon that all consoles must be set to the current var. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/console/fbcon.c | 48 +++++++++++++++++++++++++++++++++++ drivers/video/fbmem.c | 6 +++-- include/linux/fb.h | 3 +++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 35c88bd7ba5e4..751890a5f5f35 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2593,6 +2593,51 @@ static void fbcon_modechanged(struct fb_info *info) } } +static void fbcon_set_all_vcs(struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct vc_data *vc; + struct display *p; + int i, rows, cols; + + if (!ops || ops->currcon < 0) + return; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + vc = vc_cons[i].d; + if (!vc || vc->vc_mode != KD_TEXT || + registered_fb[con2fb_map[i]] != info) + continue; + + p = &fb_display[vc->vc_num]; + + info->var.xoffset = info->var.yoffset = p->yscroll = 0; + var_to_display(p, &info->var, info); + cols = info->var.xres / vc->vc_font.width; + rows = info->var.yres / vc->vc_font.height; + vc_resize(vc, cols, rows); + + if (CON_IS_VISIBLE(vc)) { + updatescrollmode(p, info, vc); + scrollback_max = 0; + scrollback_current = 0; + update_var(vc->vc_num, info); + fbcon_set_palette(vc, color_table); + update_screen(vc); + if (softback_buf) { + int l = fbcon_softback_size / vc->vc_size_row; + if (l > 5) + softback_end = softback_buf + l * vc->vc_size_row; + else { + /* Smaller scrollback makes no sense, and 0 + would screw the operation totally */ + softback_top = 0; + } + } + } + } +} + static int fbcon_mode_deleted(struct fb_info *info, struct fb_videomode *mode) { @@ -2708,6 +2753,9 @@ static int fbcon_event_notify(struct notifier_block *self, case FB_EVENT_MODE_CHANGE: fbcon_modechanged(info); break; + case FB_EVENT_MODE_CHANGE_ALL: + fbcon_set_all_vcs(info); + break; case FB_EVENT_MODE_DELETE: mode = event->data; ret = fbcon_mode_deleted(info, mode); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 4ff853fbe0bea..a8eee79e117d2 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -684,11 +684,13 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) if (!err && (flags & FBINFO_MISC_USEREVENT)) { struct fb_event event; + int evnt = (var->activate & FB_ACTIVATE_ALL) ? + FB_EVENT_MODE_CHANGE_ALL : + FB_EVENT_MODE_CHANGE; info->flags &= ~FBINFO_MISC_USEREVENT; event.info = info; - notifier_call_chain(&fb_notifier_list, - FB_EVENT_MODE_CHANGE, + notifier_call_chain(&fb_notifier_list, evnt, &event); } } diff --git a/include/linux/fb.h b/include/linux/fb.h index bc24beeed971d..70da819df0f53 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -495,6 +495,9 @@ struct fb_cursor_user { #define FB_EVENT_BLANK 0x08 /* Private modelist is to be replaced */ #define FB_EVENT_NEW_MODELIST 0x09 +/* The resolution of the passed in fb_info about to change and + all vc's should be changed */ +#define FB_EVENT_MODE_CHANGE_ALL 0x0A struct fb_event { struct fb_info *info; -- GitLab From d2d58384fc5d4c0fe2d8e34bc2d15a90a9bb372a Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:04:31 -0700 Subject: [PATCH 221/563] [PATCH] vesafb: Add blanking support Add rudimentary support by manipulating the VGA registers. However, not all vesa modes are VGA compatible, so VGA compatiblity is checked first. Only 2 levels are supported, powerup and powerdown. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/boot/video.S | 5 +++++ drivers/video/vesafb.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/tty.h | 3 ++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S index 0587477c99f2f..02bf625a681b0 100644 --- a/arch/i386/boot/video.S +++ b/arch/i386/boot/video.S @@ -97,6 +97,7 @@ #define PARAM_VESAPM_OFF 0x30 #define PARAM_LFB_PAGES 0x32 #define PARAM_VESA_ATTRIB 0x34 +#define PARAM_CAPABILITIES 0x36 /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ #ifdef CONFIG_VIDEO_RETAIN @@ -233,6 +234,10 @@ mopar_gr: movw 18(%di), %ax movl %eax, %fs:(PARAM_LFB_SIZE) +# store mode capabilities + movl 10(%di), %eax + movl %eax, %fs:(PARAM_CAPABILITIES) + # switching the DAC to 8-bit is for <= 8 bpp only movw %fs:(PARAM_LFB_DEPTH), %ax cmpw $8, %ax diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index a272592b03739..1ca80264c7b00 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -19,6 +19,7 @@ #include <linux/fb.h> #include <linux/ioport.h> #include <linux/init.h> +#include <video/vga.h> #include <asm/io.h> #include <asm/mtrr.h> @@ -54,6 +55,7 @@ static unsigned short *pmi_base = NULL; static void (*pmi_start)(void); static void (*pmi_pal)(void); static int depth; +static int vga_compat; /* --------------------------------------------------------------------- */ @@ -86,6 +88,37 @@ static int vesafb_pan_display(struct fb_var_screeninfo *var, return 0; } +static int vesafb_blank(int blank, struct fb_info *info) +{ + int err = 1; + + if (vga_compat) { + int loop = 10000; + u8 seq = 0, crtc17 = 0; + + err = 0; + + if (blank) { + seq = 0x20; + crtc17 = 0x00; + } else { + seq = 0x00; + crtc17 = 0x80; + } + + vga_wseq(NULL, 0x00, 0x01); + seq |= vga_rseq(NULL, 0x01) & ~0x20; + vga_wseq(NULL, 0x00, seq); + + crtc17 |= vga_rcrt(NULL, 0x17) & ~0x80; + while (loop--); + vga_wcrt(NULL, 0x17, crtc17); + vga_wseq(NULL, 0x00, 0x03); + } + + return err; +} + static void vesa_setpalette(int regno, unsigned red, unsigned green, unsigned blue) { @@ -176,6 +209,7 @@ static struct fb_ops vesafb_ops = { .owner = THIS_MODULE, .fb_setcolreg = vesafb_setcolreg, .fb_pan_display = vesafb_pan_display, + .fb_blank = vesafb_blank, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, @@ -429,6 +463,10 @@ static int __init vesafb_probe(struct device *device) info->flags = FBINFO_FLAG_DEFAULT | (ypan) ? FBINFO_HWACCEL_YPAN : 0; + vga_compat = (screen_info.capabilities & 2) ? 0 : 1; + printk("vesafb: Mode is %sVGA compatible\n", + (vga_compat) ? "" : "not "); + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { err = -ENOMEM; goto err; diff --git a/include/linux/tty.h b/include/linux/tty.h index 59ff42c629ece..1267f88ece6ea 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -74,7 +74,8 @@ struct screen_info { u16 vesapm_off; /* 0x30 */ u16 pages; /* 0x32 */ u16 vesa_attributes; /* 0x34 */ - /* 0x36 -- 0x3f reserved for future expansion */ + u32 capabilities; /* 0x36 */ + /* 0x3a -- 0x3f reserved for future expansion */ }; extern struct screen_info screen_info; -- GitLab From 4c7ffe0b9f7f40bd818fe3af51342f64c483908e Mon Sep 17 00:00:00 2001 From: James Simmons <jsimmons@infradead.org> Date: Fri, 9 Sep 2005 13:04:31 -0700 Subject: [PATCH 222/563] [PATCH] fbdev: prevent drivers that have hardware cursors from calling software cursor code This patch removes drivers that have hardware cursors from calling the software cursor code. Also if the driver sets a no hardware cursor flag then the driver reports a error it someone attempts to use the cursor. Signed-off-by: James Simmons <jsimmons@infradead.org> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/Kconfig | 4 ---- drivers/video/i810/i810.h | 1 - drivers/video/i810/i810_main.c | 6 ++---- drivers/video/intelfb/intelfb.h | 1 - drivers/video/intelfb/intelfbdrv.c | 21 +++------------------ drivers/video/intelfb/intelfbhw.c | 4 ---- drivers/video/nvidia/nvidia.c | 4 +--- 7 files changed, 6 insertions(+), 35 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index cde0ed097af68..3c91c3a5cc582 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -650,7 +650,6 @@ config FB_NVIDIA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This driver supports graphics boards with the nVidia chips, TNT and newer. For very old chipsets, such as the RIVA128, then use @@ -681,7 +680,6 @@ config FB_RIVA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This driver supports graphics boards with the nVidia Riva/Geforce chips. @@ -720,7 +718,6 @@ config FB_I810 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This driver supports the on-board graphics built in to the Intel 810 and 815 chipsets. Say Y if you have and plan to use such a board. @@ -763,7 +760,6 @@ config FB_INTEL select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This driver supports the on-board graphics built in to the Intel 830M/845G/852GM/855GM/865G chipsets. diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h index fe3b757947563..f59af3335ccf6 100644 --- a/drivers/video/i810/i810.h +++ b/drivers/video/i810/i810.h @@ -201,7 +201,6 @@ #define HAS_ACCELERATION 2 #define ALWAYS_SYNC 4 #define LOCKUP 8 -#define USE_HWCUR 16 struct gtt_data { struct agp_memory *i810_fb_memory; diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 6db183462b920..d07b1f203fc42 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -1375,7 +1375,6 @@ static int i810fb_set_par(struct fb_info *info) decode_var(&info->var, par); i810_load_regs(par); i810_init_cursor(par); - encode_fix(&info->fix, info); if (info->var.accel_flags && !(par->dev_flags & LOCKUP)) { @@ -1418,9 +1417,8 @@ static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor) struct i810fb_par *par = (struct i810fb_par *)info->par; u8 __iomem *mmio = par->mmio_start_virtual; - if (!(par->dev_flags & USE_HWCUR) || !info->var.accel_flags || - par->dev_flags & LOCKUP) - return soft_cursor(info, cursor); + if (!par->dev_flags & LOCKUP) + return -ENXIO; if (cursor->image.width > 64 || cursor->image.height > 64) return -ENXIO; diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 6680ec9ba69ea..011e116265583 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -234,7 +234,6 @@ struct intelfb_info { /* palette */ u32 pseudo_palette[17]; - struct { u8 red, green, blue, pad; } palette[256]; /* chip info */ int pci_chipset; diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index a112a1786855f..bf62e6ed0382c 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -117,14 +117,10 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/fb.h> -#include <linux/console.h> -#include <linux/selection.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/vmalloc.h> -#include <linux/kd.h> -#include <linux/vt_kern.h> #include <linux/pagemap.h> #include <linux/version.h> @@ -242,7 +238,7 @@ static int voffset = 48; static char *mode = NULL; module_param(accel, bool, S_IRUGO); -MODULE_PARM_DESC(accel, "Enable console acceleration"); +MODULE_PARM_DESC(accel, "Enable hardware acceleration"); module_param(vram, int, S_IRUGO); MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB"); module_param(voffset, int, S_IRUGO); @@ -498,7 +494,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) { struct fb_info *info; struct intelfb_info *dinfo; - int i, j, err, dvo; + int i, err, dvo; int aperture_size, stolen_size; struct agp_kern_info gtt_info; int agp_memtype; @@ -845,13 +841,6 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) if (bailearly == 5) bailout(dinfo); - for (i = 0; i < 16; i++) { - j = color_table[i]; - dinfo->palette[i].red = default_red[j]; - dinfo->palette[i].green = default_grn[j]; - dinfo->palette[i].blue = default_blu[j]; - } - if (bailearly == 6) bailout(dinfo); @@ -1363,10 +1352,6 @@ intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, green >>= 8; blue >>= 8; - dinfo->palette[regno].red = red; - dinfo->palette[regno].green = green; - dinfo->palette[regno].blue = blue; - intelfbhw_setcolreg(dinfo, regno, red, green, blue, transp); } @@ -1499,7 +1484,7 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) #endif if (!dinfo->hwcursor) - return soft_cursor(info, cursor); + return -ENXIO; intelfbhw_cursor_hide(dinfo); diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index f5bed581dc45f..5bafc3c54db76 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -29,14 +29,10 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/fb.h> -#include <linux/console.h> -#include <linux/selection.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/vmalloc.h> -#include <linux/kd.h> -#include <linux/vt_kern.h> #include <linux/pagemap.h> #include <linux/version.h> diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 30f80c23f934b..af99ea96012ec 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -893,7 +893,7 @@ static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor) int i, set = cursor->set; u16 fg, bg; - if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS) + if (!hwcur || cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS) return -ENXIO; NVShowHideCursor(par, 0); @@ -1356,8 +1356,6 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info) info->pixmap.size = 8 * 1024; info->pixmap.flags = FB_PIXMAP_SYSTEM; - if (!hwcur) - info->fbops->fb_cursor = soft_cursor; info->var.accel_flags = (!noaccel); switch (par->Architecture) { -- GitLab From 53eed4ec8bcd8701b9135859ec46b10a0d88ba25 Mon Sep 17 00:00:00 2001 From: David Vrabel <dvrabel@arcom.com> Date: Fri, 9 Sep 2005 13:04:32 -0700 Subject: [PATCH 223/563] [PATCH] fbdev: geode updates Geode framebuffer driver updates: - Local mode list (taken from modedb.c) containing only relevant modes. This also makes the driver work as a module. - Make it a PCI driver (from James Simmons <jsimmons@infradead.org>). - A few other minor cosmetic bits and pieces. Signed-off-by: David Vrabel <dvrabel@arcom.com> Signed-off-by: James Simmons <jsimmons@infradead.org> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/geode/Kconfig | 10 +- drivers/video/geode/geodefb.h | 1 - drivers/video/geode/gx1fb_core.c | 182 ++++++++++++++++++++++------- drivers/video/geode/video_cs5530.c | 4 +- 4 files changed, 143 insertions(+), 54 deletions(-) diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig index b075fd02de311..5a9b89c3831b1 100644 --- a/drivers/video/geode/Kconfig +++ b/drivers/video/geode/Kconfig @@ -3,15 +3,13 @@ # config FB_GEODE bool "AMD Geode family framebuffer support (EXPERIMENTAL)" - default n - depends on FB && EXPERIMENTAL && X86 + depends on FB && PCI && EXPERIMENTAL && X86 ---help--- Say 'Y' here to allow you to select framebuffer drivers for the AMD Geode family of processors. config FB_GEODE_GX1 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)" - default n depends on FB_GEODE && EXPERIMENTAL select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -21,9 +19,7 @@ config FB_GEODE_GX1 Framebuffer driver for the display controller integrated into the AMD Geode GX1 processor. - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called gx1fb. If you want to compile it as a module, - say M here and read <file:Documentation/modules.txt>. + To compile this driver as a module, choose M here: the module will be + called gx1fb. If unsure, say N. diff --git a/drivers/video/geode/geodefb.h b/drivers/video/geode/geodefb.h index b7bac0a526b38..ae04820e0c577 100644 --- a/drivers/video/geode/geodefb.h +++ b/drivers/video/geode/geodefb.h @@ -29,7 +29,6 @@ struct geodefb_par { int enable_crt; int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */ int panel_y; - struct pci_dev *vid_dev; void __iomem *dc_regs; void __iomem *vid_regs; struct geode_dc_ops *dc_ops; diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c index 83830d24bcdaa..74a5fca86b8ac 100644 --- a/drivers/video/geode/gx1fb_core.c +++ b/drivers/video/geode/gx1fb_core.c @@ -30,6 +30,62 @@ static char mode_option[32] = "640x480-16@60"; static int crt_option = 1; static char panel_option[32] = ""; +/* Modes relevant to the GX1 (taken from modedb.c) */ +static const struct fb_videomode __initdata gx1_modedb[] = { + /* 640x480-60 VESA */ + { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 640x480-75 VESA */ + { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 640x480-85 VESA */ + { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 800x600-60 VESA */ + { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 800x600-75 VESA */ + { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 800x600-85 VESA */ + { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 1024x768-60 VESA */ + { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 1024x768-75 VESA */ + { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 1024x768-85 VESA */ + { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 1280x960-60 VESA */ + { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 1280x960-85 VESA */ + { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 1280x1024-60 VESA */ + { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 1280x1024-75 VESA */ + { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, + /* 1280x1024-85 VESA */ + { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, +}; + static int gx1_line_delta(int xres, int bpp) { int line_delta = xres * (bpp >> 3); @@ -47,8 +103,6 @@ static int gx1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct geodefb_par *par = info->par; - printk(KERN_DEBUG "%s()\n", __FUNCTION__); - /* Maximum resolution is 1280x1024. */ if (var->xres > 1280 || var->yres > 1024) return -EINVAL; @@ -146,40 +200,48 @@ static int gx1fb_blank(int blank_mode, struct fb_info *info) return par->vid_ops->blank_display(info, blank_mode); } -static int __init gx1fb_map_video_memory(struct fb_info *info) +static int __init gx1fb_map_video_memory(struct fb_info *info, struct pci_dev *dev) { struct geodefb_par *par = info->par; unsigned gx_base; int fb_len; + int ret; gx_base = gx1_gx_base(); if (!gx_base) return -ENODEV; - par->vid_dev = pci_get_device(PCI_VENDOR_ID_CYRIX, - PCI_DEVICE_ID_CYRIX_5530_VIDEO, NULL); - if (!par->vid_dev) - return -ENODEV; + ret = pci_enable_device(dev); + if (ret < 0) + return ret; - par->vid_regs = ioremap(pci_resource_start(par->vid_dev, 1), - pci_resource_len(par->vid_dev, 1)); + ret = pci_request_region(dev, 1, "gx1fb (video)"); + if (ret < 0) + return ret; + par->vid_regs = ioremap(pci_resource_start(dev, 1), + pci_resource_len(dev, 1)); if (!par->vid_regs) return -ENOMEM; + if (!request_mem_region(gx_base + 0x8300, 0x100, "gx1fb (display controller)")) + return -EBUSY; par->dc_regs = ioremap(gx_base + 0x8300, 0x100); if (!par->dc_regs) return -ENOMEM; - info->fix.smem_start = gx_base + 0x800000; + ret = pci_request_region(dev, 0, "gx1fb (frame buffer)"); + if (ret < 0 ) + return -EBUSY; if ((fb_len = gx1_frame_buffer_size()) < 0) return -ENOMEM; + info->fix.smem_start = pci_resource_start(dev, 0); info->fix.smem_len = fb_len; info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) return -ENOMEM; - printk(KERN_INFO "%s: %d Kibyte of video memory at 0x%lx\n", - info->fix.id, info->fix.smem_len / 1024, info->fix.smem_start); + dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n", + info->fix.smem_len / 1024, info->fix.smem_start); return 0; } @@ -216,13 +278,13 @@ static struct fb_ops gx1fb_ops = { .fb_cursor = soft_cursor, }; -static struct fb_info * __init gx1fb_init_fbinfo(void) +static struct fb_info * __init gx1fb_init_fbinfo(struct device *dev) { - struct fb_info *info; struct geodefb_par *par; + struct fb_info *info; /* Alloc enough space for the pseudo palette. */ - info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, NULL); + info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev); if (!info) return NULL; @@ -255,47 +317,37 @@ static struct fb_info * __init gx1fb_init_fbinfo(void) /* CRT and panel options */ par->enable_crt = crt_option; if (parse_panel_option(info) < 0) - printk(KERN_WARNING "%s: invalid 'panel' option -- disabling flat panel\n", - info->fix.id); + printk(KERN_WARNING "gx1fb: invalid 'panel' option -- disabling flat panel\n"); if (!par->panel_x) par->enable_crt = 1; /* fall back to CRT if no panel is specified */ return info; } - -static struct fb_info *gx1fb_info; - -static int __init gx1fb_init(void) +static int __init gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct geodefb_par *par; struct fb_info *info; - struct geodefb_par *par; int ret; -#ifndef MODULE - if (fb_get_options("gx1fb", NULL)) - return -ENODEV; -#endif - - info = gx1fb_init_fbinfo(); + info = gx1fb_init_fbinfo(&pdev->dev); if (!info) return -ENOMEM; - gx1fb_info = info; - par = info->par; /* GX1 display controller and CS5530 video device */ par->dc_ops = &gx1_dc_ops; par->vid_ops = &cs5530_vid_ops; - if ((ret = gx1fb_map_video_memory(info)) < 0) { - printk(KERN_ERR "%s: gx1fb_map_video_memory() failed\n", info->fix.id); + if ((ret = gx1fb_map_video_memory(info, pdev)) < 0) { + dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n"); goto err; } - ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16); + ret = fb_find_mode(&info->var, info, mode_option, + gx1_modedb, ARRAY_SIZE(gx1_modedb), NULL, 16); if (ret == 0 || ret == 4) { - printk(KERN_ERR "%s: could not find valid video mode\n", info->fix.id); + dev_err(&pdev->dev, "could not find valid video mode\n"); ret = -EINVAL; goto err; } @@ -310,39 +362,83 @@ static int __init gx1fb_init(void) ret = -EINVAL; goto err; } + pci_set_drvdata(pdev, info); printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); return 0; err: - if (info->screen_base) + if (info->screen_base) { iounmap(info->screen_base); - if (par->vid_regs) + pci_release_region(pdev, 0); + } + if (par->vid_regs) { iounmap(par->vid_regs); - if (par->dc_regs) + pci_release_region(pdev, 1); + } + if (par->dc_regs) { iounmap(par->dc_regs); - if (par->vid_dev) - pci_dev_put(par->vid_dev); + release_mem_region(gx1_gx_base() + 0x8300, 0x100); + } + + pci_disable_device(pdev); + if (info) framebuffer_release(info); return ret; } -static void __exit gx1fb_cleanup(void) +static void gx1fb_remove(struct pci_dev *pdev) { - struct fb_info *info = gx1fb_info; - struct geodefb_par *par = gx1fb_info->par; + struct fb_info *info = pci_get_drvdata(pdev); + struct geodefb_par *par = info->par; unregister_framebuffer(info); iounmap((void __iomem *)info->screen_base); + pci_release_region(pdev, 0); + iounmap(par->vid_regs); + pci_release_region(pdev, 1); + iounmap(par->dc_regs); + release_mem_region(gx1_gx_base() + 0x8300, 0x100); - pci_dev_put(par->vid_dev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); framebuffer_release(info); } +static struct pci_device_id gx1fb_id_table[] = { + { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_VIDEO, + PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, + 0xff0000, 0 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, gx1fb_id_table); + +static struct pci_driver gx1fb_driver = { + .name = "gx1fb", + .id_table = gx1fb_id_table, + .probe = gx1fb_probe, + .remove = gx1fb_remove, +}; + +static int __init gx1fb_init(void) +{ +#ifndef MODULE + if (fb_get_options("gx1fb", NULL)) + return -ENODEV; +#endif + return pci_register_driver(&gx1fb_driver); +} + +static void __exit gx1fb_cleanup(void) +{ + pci_unregister_driver(&gx1fb_driver); +} + module_init(gx1fb_init); module_exit(gx1fb_cleanup); diff --git a/drivers/video/geode/video_cs5530.c b/drivers/video/geode/video_cs5530.c index d3764acf8443f..649c3943d4312 100644 --- a/drivers/video/geode/video_cs5530.c +++ b/drivers/video/geode/video_cs5530.c @@ -69,8 +69,6 @@ static const struct cs5530_pll_entry cs5530_pll_table[] = { { 4310, 0x2FB1B802, }, /* 232.0000 */ }; -#define NUM_CS5530_FREQUENCIES sizeof(cs5530_pll_table)/sizeof(struct cs5530_pll_entry) - static void cs5530_set_dclk_frequency(struct fb_info *info) { struct geodefb_par *par = info->par; @@ -82,7 +80,7 @@ static void cs5530_set_dclk_frequency(struct fb_info *info) value = cs5530_pll_table[0].pll_value; min = cs5530_pll_table[0].pixclock - info->var.pixclock; if (min < 0) min = -min; - for (i = 1; i < NUM_CS5530_FREQUENCIES; i++) { + for (i = 1; i < ARRAY_SIZE(cs5530_pll_table); i++) { diff = cs5530_pll_table[i].pixclock - info->var.pixclock; if (diff < 0L) diff = -diff; if (diff < min) { -- GitLab From 5e518d7672dea4cd7c60871e40d0490c52f01d13 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:04:34 -0700 Subject: [PATCH 224/563] [PATCH] fbdev: Resurrect hooks to get EDID from firmware For the i386, code is already present in video.S that gets the EDID from the video BIOS. Make this visible so drivers can also use this data as fallback when i2c does not work. To ensure that the EDID block is returned for the primary graphics adapter only, by check if the IORESOURCE_ROM_SHADOW flag is set. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/boot/video.S | 2 +- arch/i386/kernel/setup.c | 1 + drivers/video/fbmon.c | 35 ++++++++++++++++++++++++++++++++++- include/linux/fb.h | 4 +++- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S index 02bf625a681b0..92f6694701420 100644 --- a/arch/i386/boot/video.S +++ b/arch/i386/boot/video.S @@ -1949,7 +1949,7 @@ store_edid: movw $0x4f15, %ax # do VBE/DDC movw $0x01, %bx movw $0x00, %cx - movw $0x01, %dx + movw $0x00, %dx movw $0x140, %di int $0x10 diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index a659d274914cf..fa0c69eb937a0 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -139,6 +139,7 @@ struct sys_desc_table_struct { unsigned char table[0]; }; struct edid_info edid_info; +EXPORT_SYMBOL_GPL(edid_info); struct ist_info ist_info; #if defined(CONFIG_X86_SPEEDSTEP_SMI) || \ defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE) diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index c2718bb949493..791bec3d672af 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -29,6 +29,7 @@ #include <linux/tty.h> #include <linux/fb.h> #include <linux/module.h> +#include <video/edid.h> #ifdef CONFIG_PPC_OF #include <linux/pci.h> #include <asm/prom.h> @@ -1251,9 +1252,41 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) -EINVAL : 0; } +#if defined(__i386__) +#include <linux/pci.h> + +/* + * We need to ensure that the EDID block is only returned for + * the primary graphics adapter. + */ + +const unsigned char *fb_firmware_edid(struct device *device) +{ + struct pci_dev *dev = NULL; + struct resource *res = NULL; + unsigned char *edid = NULL; + + if (device) + dev = to_pci_dev(device); + + if (dev) + res = &dev->resource[PCI_ROM_RESOURCE]; + + if (res && res->flags & IORESOURCE_ROM_SHADOW) + edid = edid_info.dummy; + + return edid; +} +#else +const unsigned char *fb_firmware_edid(struct device *device) +{ + return NULL; +} +#endif /* _i386_ */ + EXPORT_SYMBOL(fb_parse_edid); EXPORT_SYMBOL(fb_edid_to_monspecs); - +EXPORT_SYMBOL(fb_firmware_edid); EXPORT_SYMBOL(fb_get_mode); EXPORT_SYMBOL(fb_validate_mode); EXPORT_SYMBOL(fb_destroy_modedb); diff --git a/include/linux/fb.h b/include/linux/fb.h index 70da819df0f53..e3e16f43b1bb0 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -859,7 +859,9 @@ extern int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, extern int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info); extern int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var); -extern void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs); +extern const unsigned char *fb_firmware_edid(struct device *device); +extern void fb_edid_to_monspecs(unsigned char *edid, + struct fb_monspecs *specs); extern void fb_destroy_modedb(struct fb_videomode *modedb); /* drivers/video/modedb.c */ -- GitLab From 13776711ce4b234b5ad153e55e8b5d6703c6b1ef Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:04:35 -0700 Subject: [PATCH 225/563] [PATCH] savagefb: Driver updates - Fallback to firmware EDID if chipset has no DDC/I2C support or if I2C probing failed - Add fb_blank hook - Fix savagefb_suspend/resume to enable driver to successfully suspend and resume from S3, memory or disk Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/savage/savagefb-i2c.c | 16 ++- drivers/video/savage/savagefb.h | 13 ++- drivers/video/savage/savagefb_driver.c | 139 ++++++++++++++++++++++--- 3 files changed, 147 insertions(+), 21 deletions(-) diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 847698b5cfe7d..959404ad68f43 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -259,8 +259,9 @@ static u8 *savage_do_probe_i2c_edid(struct savagefb_i2c_chan *chan) return buf; } -int savagefb_probe_i2c_connector(struct savagefb_par *par, u8 **out_edid) +int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid) { + struct savagefb_par *par = info->par; u8 *edid = NULL; int i; @@ -270,12 +271,19 @@ int savagefb_probe_i2c_connector(struct savagefb_par *par, u8 **out_edid) if (edid) break; } + + if (!edid) { + /* try to get from firmware */ + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (edid) + memcpy(edid, fb_firmware_edid(info->device), + EDID_LENGTH); + } + if (out_edid) *out_edid = edid; - if (!edid) - return 1; - return 0; + return (edid) ? 0 : 1; } MODULE_LICENSE("GPL"); diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h index 8594b1e42d718..d6f94742c9f27 100644 --- a/drivers/video/savage/savagefb.h +++ b/drivers/video/savage/savagefb.h @@ -60,6 +60,7 @@ #define S3_SAVAGE_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000)) +#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) || (chip == S3_PROSAVAGEDDR)) /* Chip tags. These are used to group the adapters into * related families. @@ -73,6 +74,8 @@ typedef enum { S3_PROSAVAGE, S3_SUPERSAVAGE, S3_SAVAGE2000, + S3_PROSAVAGEDDR, + S3_TWISTER, S3_LAST } savage_chipset; @@ -128,6 +131,10 @@ typedef enum { #define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16)) #define BCI_CMD_SEND_COLOR 0x00008000 +#define DISP_CRT 1 +#define DISP_LCD 2 +#define DISP_DFP 3 + struct xtimings { unsigned int Clock; unsigned int HDisplay; @@ -166,6 +173,10 @@ struct savagefb_par { struct savagefb_i2c_chan chan; unsigned char *edid; u32 pseudo_palette[16]; + int pm_state; + int display_type; + int dvi; + int crtonly; int dacSpeedBpp; int maxClock; int minClock; @@ -338,7 +349,7 @@ do { \ } \ } -extern int savagefb_probe_i2c_connector(struct savagefb_par *par, +extern int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid); extern void savagefb_create_i2c_busses(struct fb_info *info); extern void savagefb_delete_i2c_busses(struct fb_info *info); diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 117ad42f120d9..abad90a3702c2 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -1400,6 +1400,58 @@ static int savagefb_pan_display (struct fb_var_screeninfo *var, return 0; } +static int savagefb_blank(int blank, struct fb_info *info) +{ + struct savagefb_par *par = info->par; + u8 sr8 = 0, srd = 0; + + if (par->display_type == DISP_CRT) { + vga_out8(0x3c4, 0x08); + sr8 = vga_in8(0x3c5); + sr8 |= 0x06; + vga_out8(0x3c5, sr8); + vga_out8(0x3c4, 0x0d); + srd = vga_in8(0x3c5); + srd &= 0x03; + + switch (blank) { + case FB_BLANK_UNBLANK: + case FB_BLANK_NORMAL: + break; + case FB_BLANK_VSYNC_SUSPEND: + srd |= 0x10; + break; + case FB_BLANK_HSYNC_SUSPEND: + srd |= 0x40; + break; + case FB_BLANK_POWERDOWN: + srd |= 0x50; + break; + } + + vga_out8(0x3c4, 0x0d); + vga_out8(0x3c5, srd); + } + + if (par->display_type == DISP_LCD || + par->display_type == DISP_DFP) { + switch(blank) { + case FB_BLANK_UNBLANK: + case FB_BLANK_NORMAL: + vga_out8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */ + vga_out8(0x3c5, vga_in8(0x3c5) | 0x10); + break; + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + vga_out8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */ + vga_out8(0x3c5, vga_in8(0x3c5) & ~0x10); + break; + } + } + + return (blank == FB_BLANK_NORMAL) ? 1 : 0; +} static struct fb_ops savagefb_ops = { .owner = THIS_MODULE, @@ -1407,6 +1459,7 @@ static struct fb_ops savagefb_ops = { .fb_set_par = savagefb_set_par, .fb_setcolreg = savagefb_setcolreg, .fb_pan_display = savagefb_pan_display, + .fb_blank = savagefb_blank, #if defined(CONFIG_FB_SAVAGE_ACCEL) .fb_fillrect = savagefb_fillrect, .fb_copyarea = savagefb_copyarea, @@ -1583,8 +1636,7 @@ static int __devinit savage_init_hw (struct savagefb_par *par) static unsigned char RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 }; static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 }; - - int videoRam, videoRambytes; + int videoRam, videoRambytes, dvi; DBG("savage_init_hw"); @@ -1705,6 +1757,30 @@ static int __devinit savage_init_hw (struct savagefb_par *par) printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n", par->MCLK); + /* check for DVI/flat panel */ + dvi = 0; + + if (par->chip == S3_SAVAGE4) { + unsigned char sr30 = 0x00; + + vga_out8(0x3c4, 0x30); + /* clear bit 1 */ + vga_out8(0x3c5, vga_in8(0x3c5) & ~0x02); + sr30 = vga_in8(0x3c5); + if (sr30 & 0x02 /*0x04 */) { + dvi = 1; + printk("savagefb: Digital Flat Panel Detected\n"); + } + } + + if (S3_SAVAGE_MOBILE_SERIES(par->chip) || + (S3_MOBILE_TWISTER_SERIES(par->chip) && !par->crtonly)) + par->display_type = DISP_LCD; + else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi)) + par->display_type = DISP_DFP; + else + par->display_type = DISP_CRT; + /* Check LCD panel parrmation */ if (par->chip == S3_SAVAGE_MX) { @@ -1759,7 +1835,8 @@ static int __devinit savage_init_hw (struct savagefb_par *par) par->SavagePanelWidth = panelX; par->SavagePanelHeight = panelY; - } + } else + par->display_type = DISP_CRT; } savage_get_default_par (par); @@ -1845,15 +1922,15 @@ static int __devinit savage_init_fb_info (struct fb_info *info, snprintf (info->fix.id, 16, "ProSavageKM"); break; case FB_ACCEL_S3TWISTER_P: - par->chip = S3_PROSAVAGE; + par->chip = S3_TWISTER; snprintf (info->fix.id, 16, "TwisterP"); break; case FB_ACCEL_S3TWISTER_K: - par->chip = S3_PROSAVAGE; + par->chip = S3_TWISTER; snprintf (info->fix.id, 16, "TwisterK"); break; case FB_ACCEL_PROSAVAGE_DDR: - par->chip = S3_PROSAVAGE; + par->chip = S3_PROSAVAGEDDR; snprintf (info->fix.id, 16, "ProSavageDDR"); break; case FB_ACCEL_PROSAVAGE_DDRK: @@ -1959,7 +2036,8 @@ static int __devinit savagefb_probe (struct pci_dev* dev, INIT_LIST_HEAD(&info->modelist); #if defined(CONFIG_FB_SAVAGE_I2C) savagefb_create_i2c_busses(info); - savagefb_probe_i2c_connector(par, &par->edid); + savagefb_probe_i2c_connector(info, &par->edid); + kfree(par->edid); fb_edid_to_monspecs(par->edid, &info->monspecs); fb_videomode_to_modelist(info->monspecs.modedb, info->monspecs.modedb_len, @@ -2111,13 +2189,30 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state) DBG("savagefb_suspend"); + + par->pm_state = state.event; + + /* + * For PM_EVENT_FREEZE, do not power down so the console + * can remain active. + */ + if (state.event == PM_EVENT_FREEZE) { + dev->dev.power.power_state = state; + return 0; + } + acquire_console_sem(); - fb_set_suspend(info, pci_choose_state(dev, state)); - savage_disable_mmio(par); - release_console_sem(); + fb_set_suspend(info, 1); + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + savagefb_blank(FB_BLANK_POWERDOWN, info); + savage_disable_mmio(par); + pci_save_state(dev); pci_disable_device(dev); pci_set_power_state(dev, pci_choose_state(dev, state)); + release_console_sem(); return 0; } @@ -2127,22 +2222,34 @@ static int savagefb_resume (struct pci_dev* dev) struct fb_info *info = (struct fb_info *)pci_get_drvdata(dev); struct savagefb_par *par = (struct savagefb_par *)info->par; + int cur_state = par->pm_state; DBG("savage_resume"); - pci_set_power_state(dev, 0); - pci_restore_state(dev); - if(pci_enable_device(dev)) - DBG("err"); + par->pm_state = PM_EVENT_ON; - SavagePrintRegs(); + /* + * The adapter was not powered down coming back from a + * PM_EVENT_FREEZE. + */ + if (cur_state == PM_EVENT_FREEZE) { + pci_set_power_state(dev, PCI_D0); + return 0; + } acquire_console_sem(); + pci_set_power_state(dev, PCI_D0); + pci_restore_state(dev); + + if(pci_enable_device(dev)) + DBG("err"); + + pci_set_master(dev); savage_enable_mmio(par); savage_init_hw(par); savagefb_set_par (info); - + savagefb_blank(FB_BLANK_UNBLANK, info); fb_set_suspend (info, 0); release_console_sem(); -- GitLab From 094bb659f53b6d90aab6067268d6d14f1f352d30 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:04:36 -0700 Subject: [PATCH 226/563] [PATCH] nvidiafb: Fallback to firmware EDID If nvidiafb fails to probe the EDID block, get the EDID from the BIOS. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/nvidia/nv_i2c.c | 16 ++++++++++++---- drivers/video/nvidia/nv_proto.h | 2 +- drivers/video/nvidia/nv_setup.c | 6 +++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c index 1a91bffdda26b..ace484fa61ce0 100644 --- a/drivers/video/nvidia/nv_i2c.c +++ b/drivers/video/nvidia/nv_i2c.c @@ -194,8 +194,9 @@ static u8 *nvidia_do_probe_i2c_edid(struct nvidia_i2c_chan *chan) return NULL; } -int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, u8 **out_edid) +int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) { + struct nvidia_par *par = info->par; u8 *edid = NULL; int i; @@ -205,10 +206,17 @@ int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, u8 **out_edid) if (edid) break; } + + if (!edid && conn == 1) { + /* try to get from firmware */ + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (edid) + memcpy(edid, fb_firmware_edid(info->device), + EDID_LENGTH); + } + if (out_edid) *out_edid = edid; - if (!edid) - return 1; - return 0; + return (edid) ? 0 : 1; } diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h index 42847ce1b8dd7..cac44fc7f5871 100644 --- a/drivers/video/nvidia/nv_proto.h +++ b/drivers/video/nvidia/nv_proto.h @@ -34,7 +34,7 @@ void NVLockUnlock(struct nvidia_par *par, int); #if defined(CONFIG_FB_NVIDIA_I2C) || defined (CONFIG_PPC_OF) void nvidia_create_i2c_busses(struct nvidia_par *par); void nvidia_delete_i2c_busses(struct nvidia_par *par); -int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, +int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 ** out_edid); #else #define nvidia_create_i2c_busses(...) diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index 0bbdca2e0f911..11c84178f4206 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c @@ -401,7 +401,7 @@ void NVCommonSetup(struct fb_info *info) nvidia_create_i2c_busses(par); if (!par->twoHeads) { par->CRTCnumber = 0; - nvidia_probe_i2c_connector(par, 1, &edidA); + nvidia_probe_i2c_connector(info, 1, &edidA); if (edidA && !fb_parse_edid(edidA, &var)) { printk("nvidiafb: EDID found from BUS1\n"); monA = &monitorA; @@ -488,14 +488,14 @@ void NVCommonSetup(struct fb_info *info) oldhead = NV_RD32(par->PCRTC0, 0x00000860); NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010); - nvidia_probe_i2c_connector(par, 1, &edidA); + nvidia_probe_i2c_connector(info, 1, &edidA); if (edidA && !fb_parse_edid(edidA, &var)) { printk("nvidiafb: EDID found from BUS1\n"); monA = &monitorA; fb_edid_to_monspecs(edidA, monA); } - nvidia_probe_i2c_connector(par, 2, &edidB); + nvidia_probe_i2c_connector(info, 2, &edidB); if (edidB && !fb_parse_edid(edidB, &var)) { printk("nvidiafb: EDID found from BUS2\n"); monB = &monitorB; -- GitLab From b8c909454f046b59065c6997b651fe20cd90c0f4 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:04:37 -0700 Subject: [PATCH 227/563] [PATCH] fbdev: Fix greater than 1 bit monochrome color handling Currently, fbcon assumes that the visual FB_VISUAL_MONO* is always 1 bit. According to Geert, there are old hardware where it's possible to have monochrome at 8-bit, but has only 2 colors, black - 0x00 and white - 0xff. Fix color handlers (fb_get_color_depth, and get_color) for this special case. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/console/bitblit.c | 2 +- drivers/video/console/fbcon.c | 26 +++++++++++++-------- drivers/video/fbmem.c | 41 ++++++++++++++++++++++----------- drivers/video/nvidia/nvidia.c | 8 +++---- include/linux/fb.h | 3 ++- 5 files changed, 52 insertions(+), 28 deletions(-) diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 3c731577fed62..12eaf0aa87e6f 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -39,7 +39,7 @@ static inline int get_attribute(struct fb_info *info, u16 c) { int attribute = 0; - if (fb_get_color_depth(&info->var) == 1) { + if (fb_get_color_depth(&info->var, &info->fix) == 1) { if (attr_underline(c)) attribute |= FBCON_ATTRIBUTE_UNDERLINE; if (attr_reverse(c)) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 751890a5f5f35..88bd8ef56fde3 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -214,7 +214,7 @@ static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) static inline int get_color(struct vc_data *vc, struct fb_info *info, u16 c, int is_fg) { - int depth = fb_get_color_depth(&info->var); + int depth = fb_get_color_depth(&info->var, &info->fix); int color = 0; if (console_blanked) { @@ -230,9 +230,13 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info, switch (depth) { case 1: { + int col = ~(0xfff << (max(info->var.green.length, + max(info->var.red.length, + info->var.blue.length)))) & 0xff; + /* 0 or 1 */ - int fg = (info->fix.visual != FB_VISUAL_MONO01) ? 1 : 0; - int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : 1; + int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0; + int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col; if (console_blanked) fg = bg; @@ -246,7 +250,6 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info, * is grayscale. */ color /= 4; - break; case 3: /* * Last 8 entries of default 16-color palette is a more intense @@ -426,7 +429,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, * remove underline attribute from erase character * if black and white framebuffer. */ - if (fb_get_color_depth(&info->var) == 1) + if (fb_get_color_depth(&info->var, &info->fix) == 1) erase &= ~0x400; logo_height = fb_prepare_logo(info); logo_lines = (logo_height + vc->vc_font.height - 1) / @@ -930,7 +933,7 @@ static void fbcon_init(struct vc_data *vc, int init) } if (p->userfont) charcnt = FNTCHARCNT(p->fontdata); - vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1); + vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; if (charcnt == 256) { vc->vc_hi_font_mask = 0; @@ -1178,7 +1181,12 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, if (p->userfont) charcnt = FNTCHARCNT(p->fontdata); - vc->vc_can_do_color = (fb_get_color_depth(var) != 1); + var->activate = FB_ACTIVATE_NOW; + info->var.activate = var->activate; + info->var.yoffset = info->var.xoffset = 0; + fb_set_var(info, var); + + vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; if (charcnt == 256) { vc->vc_hi_font_mask = 0; @@ -1967,7 +1975,7 @@ static int fbcon_switch(struct vc_data *vc) set_blitting_type(vc, info, p); ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1; - vc->vc_can_do_color = (fb_get_color_depth(&info->var) != 1); + vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; updatescrollmode(p, info, vc); @@ -2332,7 +2340,7 @@ static int fbcon_set_palette(struct vc_data *vc, unsigned char *table) if (!CON_IS_VISIBLE(vc)) return 0; - depth = fb_get_color_depth(&info->var); + depth = fb_get_color_depth(&info->var, &info->fix); if (depth > 3) { for (i = j = 0; i < 16; i++) { k = table[i]; diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index a8eee79e117d2..a815f5e2fcb5b 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -62,16 +62,26 @@ int num_registered_fb; * Helpers */ -int fb_get_color_depth(struct fb_var_screeninfo *var) +int fb_get_color_depth(struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix) { - if (var->green.length == var->blue.length && - var->green.length == var->red.length && - !var->green.offset && !var->blue.offset && - !var->red.offset) - return var->green.length; - else - return (var->green.length + var->red.length + - var->blue.length); + int depth = 0; + + if (fix->visual == FB_VISUAL_MONO01 || + fix->visual == FB_VISUAL_MONO10) + depth = 1; + else { + if (var->green.length == var->blue.length && + var->green.length == var->red.length && + var->green.offset == var->blue.offset && + var->green.offset == var->red.offset) + depth = var->green.length; + else + depth = var->green.length + var->red.length + + var->blue.length; + } + + return depth; } EXPORT_SYMBOL(fb_get_color_depth); @@ -249,13 +259,18 @@ static void fb_set_logo(struct fb_info *info, const struct linux_logo *logo, u8 *dst, int depth) { - int i, j, k, fg = 1; + int i, j, k; const u8 *src = logo->data; - u8 d, xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0; + u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0; + u8 fg = 1, d; - if (fb_get_color_depth(&info->var) == 3) + if (fb_get_color_depth(&info->var, &info->fix) == 3) fg = 7; + if (info->fix.visual == FB_VISUAL_MONO01 || + info->fix.visual == FB_VISUAL_MONO10) + fg = ~((u8) (0xfff << info->var.green.length)); + switch (depth) { case 4: for (i = 0; i < logo->height; i++) @@ -318,7 +333,7 @@ static struct logo_data { int fb_prepare_logo(struct fb_info *info) { - int depth = fb_get_color_depth(&info->var); + int depth = fb_get_color_depth(&info->var, &info->fix); memset(&fb_logo, 0, sizeof(struct logo_data)); diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index af99ea96012ec..32952204ce331 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -658,7 +658,7 @@ static int nvidia_calc_regs(struct fb_info *info) { struct nvidia_par *par = info->par; struct _riva_hw_state *state = &par->ModeReg; - int i, depth = fb_get_color_depth(&info->var); + int i, depth = fb_get_color_depth(&info->var, &info->fix); int h_display = info->var.xres / 8 - 1; int h_start = (info->var.xres + info->var.right_margin) / 8 - 1; int h_end = (info->var.xres + info->var.right_margin + @@ -978,6 +978,9 @@ static int nvidiafb_set_par(struct fb_info *info) !par->twoHeads) par->FPDither = 0; + info->fix.visual = (info->var.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; + nvidia_init_vga(info); nvidia_calc_regs(info); nvidia_write_regs(par); @@ -992,9 +995,6 @@ static int nvidiafb_set_par(struct fb_info *info) NVWriteCrtc(par, 0x11, 0x00); info->fix.line_length = (info->var.xres_virtual * info->var.bits_per_pixel) >> 3; - info->fix.visual = (info->var.bits_per_pixel == 8) ? - FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; - if (info->var.accel_flags) { info->fbops->fb_imageblit = nvidiafb_imageblit; info->fbops->fb_fillrect = nvidiafb_fillrect; diff --git a/include/linux/fb.h b/include/linux/fb.h index e3e16f43b1bb0..c71a7162e0983 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -823,7 +823,8 @@ extern void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height, u32 shift_high, u32 shift_low, u32 mod); extern void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height); extern void fb_set_suspend(struct fb_info *info, int state); -extern int fb_get_color_depth(struct fb_var_screeninfo *var); +extern int fb_get_color_depth(struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix); extern int fb_get_options(char *name, char **option); extern int fb_new_modelist(struct fb_info *info); -- GitLab From 2cc38ed13f1b0f9d80a2d0acc2916af94922f27e Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:04:38 -0700 Subject: [PATCH 228/563] [PATCH] fbcon: Saner 16-color to 4-color conversion Currently, the default linux 16-colors are converted to 4-colors by simply dividing the values by 4. However, this is not necessarily correct since the first 4 colors are converted to black, rendering them invisible. So, for black, no conversion; for light colors, convert to gray, for normal text color, no conversion, and for bright colors, convert to intense white. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/console/fbcon.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 88bd8ef56fde3..bb4ea50b54a33 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -247,9 +247,26 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info, case 2: /* * Scale down 16-colors to 4 colors. Default 4-color palette - * is grayscale. + * is grayscale. However, simply dividing the values by 4 + * will not work, as colors 1, 2 and 3 will be scaled-down + * to zero rendering them invisible. So empirically convert + * colors to a sane 4-level grayscale. */ - color /= 4; + switch (color) { + case 0: + color = 0; /* black */ + break; + case 1 ... 6: + color = 2; /* white */ + break; + case 7 ... 8: + color = 1; /* gray */ + break; + default: + color = 3; /* intense white */ + break; + } + break; case 3: /* * Last 8 entries of default 16-color palette is a more intense -- GitLab From 3b41dc1a3c7839a765ffa560a5ae07aa5d253cc8 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:04:39 -0700 Subject: [PATCH 229/563] [PATCH] console: Fix buffer copy on vc resize On a vc resize, the contents of the old screen buffer are transferred to the new screenbuffer. If the new screenbuffer is smaller than the old one, only the contents from the bottom are copied to new. If the contents of the old buffer are located at the top, then the contents will not be copied to the new buffer resulting in a blank screen. This bug will happen only if the vc in question is not in the foreground. Doing an fbset -a or con2fbmap will trigger this bug. To fix this problem, base the start of the copy from the location of the current cursor. If the cursor is near the top of the buffer, copy the contents at the top, and if the cursor is near the bottom of the buffer, then copy the contents at the bottom. In the unlikely case where the new row size is greater than 2x smaller than the old one, and the cursor is in the middle, copy 1/2 screenful from the top and bottom of the cursor position. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/vt.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/char/vt.c b/drivers/char/vt.c index b8d0c290b0dbf..1e33cb032e073 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -751,6 +751,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; unsigned int old_cols, old_rows, old_row_size, old_screen_size; unsigned int new_cols, new_rows, new_row_size, new_screen_size; + unsigned int end; unsigned short *newscreen; WARN_CONSOLE_UNLOCKED(); @@ -794,20 +795,44 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) old_origin = vc->vc_origin; new_origin = (long) newscreen; new_scr_end = new_origin + new_screen_size; - if (new_rows < old_rows) - old_origin += (old_rows - new_rows) * old_row_size; + + if (vc->vc_y > new_rows) { + if (old_rows - vc->vc_y < new_rows) { + /* + * Cursor near the bottom, copy contents from the + * bottom of buffer + */ + old_origin += (old_rows - new_rows) * old_row_size; + end = vc->vc_scr_end; + } else { + /* + * Cursor is in no man's land, copy 1/2 screenful + * from the top and bottom of cursor position + */ + old_origin += (vc->vc_y - new_rows/2) * old_row_size; + end = old_origin + new_screen_size; + } + } else + /* + * Cursor near the top, copy contents from the top of buffer + */ + end = (old_rows > new_rows) ? old_origin + new_screen_size : + vc->vc_scr_end; update_attr(vc); - while (old_origin < vc->vc_scr_end) { - scr_memcpyw((unsigned short *) new_origin, (unsigned short *) old_origin, rlth); + while (old_origin < end) { + scr_memcpyw((unsigned short *) new_origin, + (unsigned short *) old_origin, rlth); if (rrem) - scr_memsetw((void *)(new_origin + rlth), vc->vc_video_erase_char, rrem); + scr_memsetw((void *)(new_origin + rlth), + vc->vc_video_erase_char, rrem); old_origin += old_row_size; new_origin += new_row_size; } if (new_scr_end > new_origin) - scr_memsetw((void *)new_origin, vc->vc_video_erase_char, new_scr_end - new_origin); + scr_memsetw((void *)new_origin, vc->vc_video_erase_char, + new_scr_end - new_origin); if (vc->vc_kmalloced) kfree(vc->vc_screenbuf); vc->vc_screenbuf = newscreen; -- GitLab From 2a43b58589eac1fdcf62624e86c67c0f92f45bf7 Mon Sep 17 00:00:00 2001 From: Alexander Kern <alex.kern@gmx.de> Date: Fri, 9 Sep 2005 13:04:40 -0700 Subject: [PATCH 230/563] [PATCH] atyfb: Remove code that sets sync polarity unconditionally Currently, atyfb has code that sets the hsync and vsync polarity based on the current video mode, without letting the user override the settings. Remove this particular code. The sync polarities are set by the PROM, the user or by the videomode. Signed-off-by: Alexander Kern <alex.kern@gmx.de> Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/aty/atyfb_base.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 3e10bd837d9e8..037fe9d32fe39 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -911,20 +911,6 @@ static int aty_var_to_crtc(const struct fb_info *info, vdisplay = par->lcd_height; #endif - if(vdisplay < 400) { - h_sync_pol = 1; - v_sync_pol = 0; - } else if(vdisplay < 480) { - h_sync_pol = 0; - v_sync_pol = 1; - } else if(vdisplay < 768) { - h_sync_pol = 0; - v_sync_pol = 0; - } else { - h_sync_pol = 1; - v_sync_pol = 1; - } - v_disp--; v_sync_strt--; v_sync_end--; -- GitLab From f510a3c3d48fd5aaa7757aebbc37e9ee417913a3 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:04:41 -0700 Subject: [PATCH 231/563] [PATCH] radeonfb_old: Fix broken link The link for ATI's product page in drivers/video/Kconfig for FB_RADEON is broken. Replace with a product comparison page. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3c91c3a5cc582..544c717c6ee45 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -956,8 +956,7 @@ config FB_RADEON can be build either as modules or built-in. There is a product page at - <http://www.ati.com/na/pages/products/pc/radeon32/index.html>. - + http://apps.ati.com/ATIcompare/ config FB_RADEON_I2C bool "DDC/I2C for ATI Radeon support" depends on FB_RADEON -- GitLab From 5c06e2aa6339112befdc87b350b8bf712890d7a7 Mon Sep 17 00:00:00 2001 From: Ian Romanick <idr@us.ibm.com> Date: Fri, 9 Sep 2005 13:04:42 -0700 Subject: [PATCH 232/563] [PATCH] matroxfb: read MGA PInS data on PowerPC This updates the matroxfb code so that it can find the PInS data embedded in the BIOS on PowerPC cards. The process for finding the data is different on OpenFirmware cards than on x86 cards, and the code for doing so was missing. After patching, building, installing, and booting a kernel, you should grep for "PInS" in /var/log/messages. You should see two messages in the log: PInS data found at offset XXXXX PInS memtype = X On the GXT135p card I get "31168" and "5". The first value is irrelevant, but it's presence lets me know that the PInS data was actually found. On a GXT130p, the second value should be 3. Since I don't have access to that hardware, if someone can verify that, I will submit a follow-on patch that rips out all the memtype parameter stuff. Signed-off-by: Ian Romanick <idr@us.ibm.com> Signed-off-by: Petr Vandrovec <vandrove@vc.cvut.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/matrox/matroxfb_misc.c | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c index a18dd024fc86a..d9d3e9f6c08e2 100644 --- a/drivers/video/matrox/matroxfb_misc.c +++ b/drivers/video/matrox/matroxfb_misc.c @@ -68,6 +68,9 @@ * "David C. Hansen" <haveblue@us.ibm.com> * Fixes * + * "Ian Romanick" <idr@us.ibm.com> + * Find PInS data in BIOS on PowerPC systems. + * * (following author is not in any relation with this code, but his code * is included in this driver) * @@ -496,10 +499,35 @@ static void parse_bios(unsigned char __iomem* vbios, struct matrox_bios* bd) { get_bios_version(vbios, bd); get_bios_output(vbios, bd); get_bios_tvout(vbios, bd); +#if defined(__powerpc__) + /* On PowerPC cards, the PInS offset isn't stored at the end of the + * BIOS image. Instead, you must search the entire BIOS image for + * the magic PInS signature. + * + * This actually applies to all OpenFirmware base cards. Since these + * cards could be put in a MIPS or SPARC system, should the condition + * be something different? + */ + for ( pins_offset = 0 ; pins_offset <= 0xFF80 ; pins_offset++ ) { + unsigned char header[3]; + + header[0] = readb(vbios + pins_offset); + header[1] = readb(vbios + pins_offset + 1); + header[2] = readb(vbios + pins_offset + 2); + if ( (header[0] == 0x2E) && (header[1] == 0x41) + && ((header[2] == 0x40) || (header[2] == 0x80)) ) { + printk(KERN_INFO "PInS data found at offset %u\n", + pins_offset); + get_pins(vbios + pins_offset, bd); + break; + } + } +#else pins_offset = readb(vbios + 0x7FFC) | (readb(vbios + 0x7FFD) << 8); if (pins_offset <= 0xFF80) { get_pins(vbios + pins_offset, bd); } +#endif } #define get_u16(x) (le16_to_cpu(get_unaligned((__u16*)(x)))) @@ -755,6 +783,8 @@ void matroxfb_read_pins(WPMINFO2) { } #endif matroxfb_set_limits(PMINFO &ACCESS_FBINFO(bios)); + printk(KERN_INFO "PInS memtype = %u\n", + (ACCESS_FBINFO(values).reg.opt & 0x1C00) >> 10); } EXPORT_SYMBOL(matroxfb_DAC_in); -- GitLab From 544393fe584d333480659a4bed30f5295355df11 Mon Sep 17 00:00:00 2001 From: Thomas Winischhofer <thomas@winischhofer.net> Date: Fri, 9 Sep 2005 13:04:45 -0700 Subject: [PATCH 233/563] [PATCH] sisfb update This lifts sisfb from version 1.7.17 to version 1.8.9. Changes include: - Added support for XGI V3XT, V5, V8, Z7 chipsets, including POSTing of all of these chipsets. - Added support for latest SiS chipsets (761). - Added support for SiS76x memory "hybrid" mode. - Added support for new LCD resolutions (eg 1280x854, 856x480). - Fixed support for 320x240 STN panels (for embedded devices). - Fixed many HDTV modes (525p, 750p, 1080i). - Fixed PCI config register reading/writing to use proper kernel functions for this purpose. - Fixed PCI ROM handling to use the kernel's proper functions. - Removed lots of "typedef"s. - Removed lots of code which was for X.org/XFree86 only. - Fixed coding style in many places. - Removed lots of 2.4 cruft. - Reduced stack size by unifying two previously separate structs into one. - Added new hooks for memory allocation (for DRM). Now the driver can truly handle multiple cards, including memory management. - Fixed numerous minor bugs. Signed-off-by: Thomas Winischhofer <thomas@winischhofer.net> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/Kconfig | 14 +- drivers/video/sis/300vtbl.h | 1363 +---- drivers/video/sis/310vtbl.h | 2125 ++----- drivers/video/sis/Makefile | 2 +- drivers/video/sis/init.c | 5649 ++++++++----------- drivers/video/sis/init.h | 1732 ++---- drivers/video/sis/init301.c | 9668 ++++++++++++++------------------ drivers/video/sis/init301.h | 351 +- drivers/video/sis/initdef.h | 145 +- drivers/video/sis/initextlfb.c | 238 + drivers/video/sis/oem300.h | 335 +- drivers/video/sis/oem310.h | 421 +- drivers/video/sis/osdef.h | 27 +- drivers/video/sis/sis.h | 746 +-- drivers/video/sis/sis_accel.c | 479 +- drivers/video/sis/sis_accel.h | 9 +- drivers/video/sis/sis_main.c | 7839 +++++++++++++++----------- drivers/video/sis/sis_main.h | 602 +- drivers/video/sis/vgatypes.h | 155 +- drivers/video/sis/vstruct.h | 1097 ++-- include/linux/fb.h | 2 + include/video/sisfb.h | 188 +- 22 files changed, 14534 insertions(+), 18653 deletions(-) create mode 100644 drivers/video/sis/initextlfb.c diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 544c717c6ee45..e906b54217951 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1079,15 +1079,16 @@ config FB_SAVAGE_ACCEL choose N here. config FB_SIS - tristate "SiS acceleration" + tristate "SiS/XGI display support" depends on FB && PCI select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select FB_SOFT_CURSOR help - This is the frame buffer device driver for the SiS 300, 315 and - 330 series VGA chipsets. Specs available at <http://www.sis.com> + This is the frame buffer device driver for the SiS 300, 315, 330 + and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets. + Specs available at <http://www.sis.com> and <http://www.xgitech.com>. To compile this driver as a module, choose M here; the module will be called sisfb. @@ -1099,11 +1100,12 @@ config FB_SIS_300 Say Y here to support use of the SiS 300/305, 540, 630 and 730. config FB_SIS_315 - bool "SiS 315/330 series support" + bool "SiS 315/330/340 series and XGI support" depends on FB_SIS help - Say Y here to support use of the SiS 315 and 330 series - (315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760). + Say Y here to support use of the SiS 315, 330 and 340 series + (315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760, 761) as well + as XGI V3XT, V5, V8 and Z7. config FB_NEOMAGIC tristate "NeoMagic display support" diff --git a/drivers/video/sis/300vtbl.h b/drivers/video/sis/300vtbl.h index b6d5c71b25630..e4b4a2626da46 100644 --- a/drivers/video/sis/300vtbl.h +++ b/drivers/video/sis/300vtbl.h @@ -3,7 +3,7 @@ /* * Register settings for SiS 300 series * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -50,31 +50,7 @@ * */ -static const SiS_StStruct SiS300_SModeIDTable[] = -{ - {0x01,0x9208,0x01,0x00,0x00,0x00,0x00,0x00, 0}, - {0x01,0x1210,0x14,0x01,0x01,0x00,0x00,0x00, 0}, - {0x01,0x1010,0x17,0x02,0x02,0x00,0x00,0x00, 0}, - {0x03,0x8208,0x03,0x00,0x00,0x00,0x00,0x00, 0}, - {0x03,0x0210,0x16,0x01,0x01,0x00,0x00,0x00, 0}, - {0x03,0x0010,0x18,0x02,0x02,0x00,0x00,0x00, 0}, - {0x05,0x9209,0x05,0x00,0x00,0x00,0x00,0x00, 0}, - {0x06,0x8209,0x06,0x00,0x00,0x00,0x00,0x00, 0}, - {0x07,0x0000,0x07,0x03,0x03,0x00,0x00,0x00, 0}, - {0x07,0x0000,0x19,0x02,0x02,0x00,0x00,0x00, 0}, - {0x0d,0x920a,0x0d,0x00,0x00,0x00,0x00,0x00, 0}, - {0x0e,0x820a,0x0e,0x00,0x00,0x00,0x00,0x00, 0}, - {0x0f,0x0202,0x11,0x01,0x01,0x00,0x00,0x00, 0}, - {0x10,0x0212,0x12,0x01,0x01,0x00,0x00,0x00, 0}, - {0x11,0x0212,0x1a,0x04,0x04,0x00,0x00,0x00, 0}, - {0x12,0x0212,0x1b,0x04,0x04,0x00,0x00,0x00, 0}, - {0x13,0x021b,0x1c,0x00,0x00,0x00,0x00,0x00, 0}, - {0x12,0x0010,0x18,0x02,0x02,0x00,0x00,0x00, 0}, - {0x12,0x0210,0x18,0x01,0x01,0x00,0x00,0x00, 0}, - {0xff, 0, 0, 0, 0, 0, 0, 0, 0} -}; - -static const SiS_ExtStruct SiS300_EModeIDTable[] = +static const struct SiS_Ext SiS300_EModeIDTable[] = { {0x6a,0x2212,0x0102,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, /* 800x600x? */ {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08,-1}, @@ -110,7 +86,7 @@ static const SiS_ExtStruct SiS300_EModeIDTable[] = {0x59,0x921b,0x0138,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23,-1}, /* 320x200x8 */ {0x5c,0x921f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26,-1}, /* 512x384x32 */ {0x5d,0x021d,0x0139,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10,-1}, /* 640x400x16 */ - {0x5e,0x021f,0x0000,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10,-1}, /* 640x400x32 */ + {0x5e,0x021f,0x0000,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10,-1}, /* 640x400x32 */ {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08,-1}, {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00,-1}, /* 800x600x32 */ {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1}, @@ -119,8 +95,8 @@ static const SiS_ExtStruct SiS300_EModeIDTable[] = {0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1}, {0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1}, {0x6b,0x07ff,0x0000,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1}, - {0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1}, /* 2048x1536x8 - not in BIOS! */ - {0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1}, /* 2048x1536x16 - not in BIOS! */ + {0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1}, /* 2048x1536x8 */ + {0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1}, /* 2048x1536x16 */ {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d,-1}, /* 800x480x8 */ {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1}, /* 1024x576x8 */ {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1}, /* 1024x576x16 */ @@ -166,77 +142,77 @@ static const SiS_ExtStruct SiS300_EModeIDTable[] = {0xff,0x0000,0xffff,0, 0x00,0x00,0x00,0x00,0x00} }; -static const SiS_Ext2Struct SiS300_RefIndex[] = -{ - {0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0}, /* 00 */ - {0x0467,0x0e,0x44,0x05,0x05,0x6a, 800, 600, 0}, /* 01 */ - {0x0067,0x0f,0x07,0x48,0x05,0x6a, 800, 600, 0}, /* 02 - CRT1CRTC was 0x4f */ - {0x0067,0x10,0x06,0x8b,0x05,0x6a, 800, 600, 0}, /* 03 */ - {0x0147,0x11,0x08,0x00,0x05,0x6a, 800, 600, 0}, /* 04 */ - {0x0147,0x12,0x0c,0x00,0x05,0x6a, 800, 600, 0}, /* 05 */ - {0x0047,0x11,0x4e,0x00,0x05,0x6a, 800, 600, 0}, /* 06 - CRT1CRTC was 0x51 */ - {0x0047,0x11,0x13,0x00,0x05,0x6a, 800, 600, 0}, /* 07 */ - {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0}, /* 08 */ - {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0}, /* 09 */ - {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0}, /* 0a */ - {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0}, /* 0b */ - {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0}, /* 0c */ - {0xc047,0x0a,0x08,0x00,0x04,0x2e, 640, 480, 0}, /* 0d */ - {0xc047,0x0b,0x0a,0x00,0x04,0x2e, 640, 480, 0}, /* 0e */ - {0xc047,0x0c,0x10,0x00,0x04,0x2e, 640, 480, 0}, /* 0f */ - {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0}, /* 10 */ - {0xc06f,0x31,0x01,0x06,0x13,0x31, 720, 480, 0}, /* 11 */ - {0x006f,0x32,0x03,0x06,0x14,0x32, 720, 576, 0}, /* 12 */ - {0x0187,0x15,0x05,0x00,0x06,0x37,1024, 768, 0}, /* 13 */ - {0xc877,0x16,0x09,0x06,0x06,0x37,1024, 768, 0}, /* 14 */ - {0xc067,0x17,0x0b,0x49,0x06,0x37,1024, 768, 0}, /* 15 - CRT1CRTC was 0x97 */ - {0x0267,0x18,0x0d,0x00,0x06,0x37,1024, 768, 0}, /* 16 */ - {0x0047,0x19,0x11,0x8c,0x06,0x37,1024, 768, 0}, /* 17 - CRT1CRTC was 0x59 */ - {0x0047,0x1a,0x52,0x00,0x06,0x37,1024, 768, 0}, /* 18 */ - {0x0007,0x1b,0x16,0x00,0x06,0x37,1024, 768, 0}, /* 19 - CRT1CRTC was 0x5b */ - {0x0387,0x1c,0x4d,0x00,0x07,0x3a,1280,1024, 0}, /* 1a - CRT1CRTC was 0x5c */ - {0x0077,0x1d,0x14,0x07,0x07,0x3a,1280,1024, 0}, /* 1b */ - {0x0047,0x1e,0x17,0x00,0x07,0x3a,1280,1024, 0}, /* 1c */ - {0x0007,0x1f,0x98,0x00,0x07,0x3a,1280,1024, 0}, /* 1d */ - {0x0007,0x20,0x59,0x00,0x00,0x3c,1600,1200, 0}, /* 1e - CRT1CRTC was 0x60 */ - {0x0007,0x21,0x5a,0x00,0x00,0x3c,1600,1200, 0}, /* 1f */ - {0x0007,0x22,0x1b,0x00,0x00,0x3c,1600,1200, 0}, /* 20 */ - {0x0007,0x23,0x1d,0x00,0x00,0x3c,1600,1200, 0}, /* 21 - CRT1CRTC was 0x63 */ - {0x0007,0x24,0x1e,0x00,0x00,0x3c,1600,1200, 0}, /* 22 */ - {0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0}, /* 23 */ - {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0}, /* 24 */ - {0x0077,0x02,0x04,0x05,0x05,0x51, 400, 300, 0}, /* 25 */ - {0xc877,0x03,0x09,0x06,0x06,0x52, 512, 384, 0}, /* 26 */ /* was c077 */ - {0x8207,0x25,0x1f,0x00,0x00,0x68,1920,1440, 0}, /* 27 */ - {0x0007,0x26,0x20,0x00,0x00,0x6c,2048,1536, 0}, /* 28 */ - {0x0067,0x27,0x14,0x08,0x0a,0x6e,1280, 960, 0}, /* 29 - 1280x960-60 */ - {0x0027,0x45,0x3c,0x08,0x0a,0x6e,1280, 960, 0}, /* 2a - 1280x960-85 */ - {0xc077,0x33,0x09,0x06,0x00,0x20,1024, 600, 0}, /* 2b */ - {0xc077,0x34,0x0b,0x06,0x00,0x23,1152, 768, 0}, /* 2c */ /* VCLK 0x09 */ - {0x0077,0x35,0x27,0x08,0x18,0x70, 800, 480, 0}, /* 2d */ - {0x0047,0x36,0x37,0x08,0x18,0x70, 800, 480, 0}, /* 2e */ - {0x0047,0x37,0x08,0x08,0x18,0x70, 800, 480, 0}, /* 2f */ - {0x0077,0x38,0x09,0x09,0x19,0x71,1024, 576, 0}, /* 30 */ - {0x0047,0x39,0x38,0x09,0x19,0x71,1024, 576, 0}, /* 31 */ - {0x0047,0x3a,0x11,0x09,0x19,0x71,1024, 576, 0}, /* 32 */ - {0x0077,0x3b,0x39,0x0a,0x0c,0x75,1280, 720, 0}, /* 33 */ - {0x0047,0x3c,0x3a,0x0a,0x0c,0x75,1280, 720, 0}, /* 34 */ - {0x0007,0x3d,0x3b,0x0a,0x0c,0x75,1280, 720, 0}, /* 35 */ - {0x0067,0x49,0x35,0x06,0x1a,0x29,1152, 864, 0}, /* 36 1152x864-60Hz */ - {0x0067,0x3e,0x34,0x06,0x1a,0x29,1152, 864, 0}, /* 37 1152x864-75Hz */ - {0x0047,0x44,0x3a,0x06,0x1a,0x29,1152, 864, 0}, /* 38 1152x864-85Hz */ - {0x00c7,0x3f,0x28,0x00,0x16,0x39, 848, 480, 0}, /* 39 848x480-38Hzi */ - {0xc067,0x40,0x3d,0x0b,0x16,0x39, 848, 480, 0}, /* 3a 848x480-60Hz */ - {0x00c7,0x41,0x28,0x00,0x17,0x3f, 856, 480, 0}, /* 3b 856x480-38Hzi */ - {0xc047,0x42,0x28,0x00,0x17,0x3f, 856, 480, 0}, /* 3c 856x480-60Hz */ - {0x0067,0x43,0x3e,0x0c,0x1b,0x48,1360, 768, 0}, /* 3d 1360x768-60Hz */ - {0x0077,0x46,0x3f,0x08,0x08,0x55,1280, 768, 0}, /* 3e 1280x768-60Hz */ - {0x006f,0x47,0x03,0x06,0x15,0x5f, 768, 576, 0}, /* 3f 768x576 */ - {0x0027,0x48,0x13,0x08,0x00,0x67,1360,1024, 0}, /* 40 1360x1024-59Hz (BARCO1366 only) */ - {0xffff, 0, 0, 0, 0, 0, 0, 0, 0} -}; - -static const SiS_VBModeStruct SiS300_VBModeIDTable[] = +static const struct SiS_Ext2 SiS300_RefIndex[] = +{ + {0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 00 */ + {0x0467,0x0e,0x04,0x05,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 01 */ + {0x0067,0x0f,0x07,0x48,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 02 - CRT1CRTC was 0x4f */ + {0x0067,0x10,0x06,0x8b,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 03 */ + {0x0147,0x11,0x08,0x00,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 04 */ + {0x0147,0x12,0x0c,0x00,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 05 */ + {0x0047,0x11,0x0e,0x00,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 06 - CRT1CRTC was 0x51 */ + {0x0047,0x11,0x13,0x00,0x05,0x6a, 800, 600, 0, 0x00, 0x00}, /* 07 */ + {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 08 */ + {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 09 */ + {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0a */ + {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0b */ + {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0c */ + {0xc047,0x0a,0x08,0x00,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0d */ + {0xc047,0x0b,0x0a,0x00,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0e */ + {0xc047,0x0c,0x10,0x00,0x04,0x2e, 640, 480, 0, 0x00, 0x00}, /* 0f */ + {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0, 0x4a, 0x49}, /* 10 */ + {0xc06f,0x31,0x01,0x06,0x13,0x31, 720, 480, 0, 0x00, 0x00}, /* 11 */ + {0x006f,0x32,0x4a,0x06,0x14,0x32, 720, 576, 0, 0x00, 0x00}, /* 12 */ /* 4a was 03 */ + {0x0187,0x15,0x05,0x00,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 13 */ + {0xc877,0x16,0x09,0x06,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 14 */ + {0xc067,0x17,0x0b,0x49,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 15 - CRT1CRTC was 0x97 */ + {0x0267,0x18,0x0d,0x00,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 16 */ + {0x0047,0x19,0x11,0x8c,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 17 - CRT1CRTC was 0x59 */ + {0x0047,0x1a,0x12,0x00,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 18 */ + {0x0007,0x1b,0x16,0x00,0x06,0x37,1024, 768, 0, 0x00, 0x00}, /* 19 - CRT1CRTC was 0x5b */ + {0x0387,0x1c,0x0d,0x00,0x07,0x3a,1280,1024, 0, 0x00, 0x00}, /* 1a - CRT1CRTC was 0x5c */ + {0x0077,0x1d,0x14,0x07,0x07,0x3a,1280,1024, 0, 0x00, 0x00}, /* 1b */ + {0x0047,0x1e,0x17,0x00,0x07,0x3a,1280,1024, 0, 0x00, 0x00}, /* 1c */ + {0x0007,0x1f,0x18,0x00,0x07,0x3a,1280,1024, 0, 0x00, 0x00}, /* 1d */ + {0x0007,0x20,0x19,0x00,0x00,0x3c,1600,1200, 0, 0x00, 0x00}, /* 1e - CRT1CRTC was 0x60 */ + {0x0007,0x21,0x1a,0x00,0x00,0x3c,1600,1200, 0, 0x00, 0x00}, /* 1f */ + {0x0007,0x22,0x1b,0x00,0x00,0x3c,1600,1200, 0, 0x00, 0x00}, /* 20 */ + {0x0007,0x23,0x1d,0x00,0x00,0x3c,1600,1200, 0, 0x00, 0x00}, /* 21 - CRT1CRTC was 0x63 */ + {0x0007,0x24,0x1e,0x00,0x00,0x3c,1600,1200, 0, 0x00, 0x00}, /* 22 */ + {0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0, 0x4b, 0x4b}, /* 23 */ + {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0, 0x00, 0x00}, /* 24 */ + {0x0077,0x02,0x04,0x05,0x05,0x51, 400, 300, 0, 0x00, 0x00}, /* 25 */ + {0xc877,0x03,0x09,0x06,0x06,0x52, 512, 384, 0, 0x00, 0x00}, /* 26 */ /* was c077 */ + {0x8207,0x25,0x1f,0x00,0x00,0x68,1920,1440, 0, 0x00, 0x00}, /* 27 */ + {0x0007,0x26,0x20,0x00,0x00,0x6c,2048,1536, 0, 0x00, 0x00}, /* 28 */ + {0x0067,0x27,0x14,0x08,0x0a,0x6e,1280, 960, 0, 0x00, 0x00}, /* 29 - 1280x960-60 */ + {0x0027,0x45,0x3c,0x08,0x0a,0x6e,1280, 960, 0, 0x00, 0x00}, /* 2a - 1280x960-85 */ + {0xc077,0x33,0x09,0x06,0x00,0x20,1024, 600, 0, 0x00, 0x00}, /* 2b */ + {0xc077,0x34,0x0b,0x06,0x00,0x23,1152, 768, 0, 0x00, 0x00}, /* 2c */ /* VCLK 0x09 */ + {0x0077,0x35,0x27,0x08,0x18,0x70, 800, 480, 0, 0x00, 0x00}, /* 2d */ + {0x0047,0x36,0x37,0x08,0x18,0x70, 800, 480, 0, 0x00, 0x00}, /* 2e */ + {0x0047,0x37,0x08,0x08,0x18,0x70, 800, 480, 0, 0x00, 0x00}, /* 2f */ + {0x0077,0x38,0x09,0x09,0x19,0x71,1024, 576, 0, 0x00, 0x00}, /* 30 */ + {0x0047,0x39,0x38,0x09,0x19,0x71,1024, 576, 0, 0x00, 0x00}, /* 31 */ + {0x0047,0x3a,0x11,0x09,0x19,0x71,1024, 576, 0, 0x00, 0x00}, /* 32 */ + {0x0077,0x3b,0x39,0x0a,0x0c,0x75,1280, 720, 0, 0x00, 0x00}, /* 33 */ + {0x0047,0x3c,0x3a,0x0a,0x0c,0x75,1280, 720, 0, 0x00, 0x00}, /* 34 */ + {0x0007,0x3d,0x3b,0x0a,0x0c,0x75,1280, 720, 0, 0x00, 0x00}, /* 35 */ + {0x0067,0x49,0x35,0x06,0x1a,0x29,1152, 864, 0, 0x00, 0x00}, /* 36 1152x864-60Hz */ + {0x0067,0x3e,0x34,0x06,0x1a,0x29,1152, 864, 0, 0x00, 0x00}, /* 37 1152x864-75Hz */ + {0x0047,0x44,0x3a,0x06,0x1a,0x29,1152, 864, 0, 0x00, 0x00}, /* 38 1152x864-85Hz */ + {0x00c7,0x3f,0x28,0x00,0x16,0x39, 848, 480, 0, 0x00, 0x00}, /* 39 848x480-38Hzi */ + {0xc067,0x40,0x3d,0x0b,0x16,0x39, 848, 480, 0, 0x00, 0x00}, /* 3a 848x480-60Hz */ + {0x00c7,0x41,0x28,0x00,0x17,0x3f, 856, 480, 0, 0x00, 0x00}, /* 3b 856x480-38Hzi */ + {0xc067,0x42,0x28,0x0c,0x17,0x3f, 856, 480, 0, 0x00, 0x00}, /* 3c 856x480-60Hz */ + {0x0067,0x43,0x3e,0x0d,0x1b,0x48,1360, 768, 0, 0x00, 0x00}, /* 3d 1360x768-60Hz */ + {0x0077,0x46,0x3f,0x08,0x08,0x55,1280, 768, 0, 0x00, 0x00}, /* 3e 1280x768-60Hz */ + {0x006f,0x47,0x4c,0x06,0x15,0x5f, 768, 576, 0, 0x00, 0x00}, /* 3f 768x576 */ + {0x0027,0x48,0x13,0x08,0x00,0x67,1360,1024, 0, 0x00, 0x00}, /* 40 1360x1024-59Hz (BARCO1366 only) */ + {0xffff, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00} +}; + +static const struct SiS_VBMode SiS300_VBModeIDTable[] = { {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, @@ -303,53 +279,26 @@ static const SiS_VBModeStruct SiS300_VBModeIDTable[] = {0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }; -static const SiS_CRT1TableStruct SiS300_CRT1Table[] = +static const struct SiS_CRT1Table SiS300_CRT1Table[] = { -#if 1 {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, /* 0x00 - 320x200 */ 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, /* HRE [4],[15] is invalid - but correcting it does not work */ 0x00}}, -#endif -#if 0 - {{0x2d,0x27,0x27,0x91,0x2c,0x92,0xbf,0x1f, /* 0x00 - corrected 320x200-72 - does not work */ - 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x04, - 0x00}}, -#endif {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, /* 0x01 */ 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, /* HRE [4],[15] is invalid - but correcting it does not work */ 0x00}}, -#if 0 - {{0x2d,0x27,0x27,0x91,0x2c,0x92,0x0b,0x3e, /* 0x01 - corrected 320x240-60 - does not work */ - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x04, - 0x00}}, -#endif {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, /* 0x02 */ 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, 0x01}}, -#if 0 - {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, /* 0x02 - corrected 400x300-60 */ - 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, - 0x01}}, -#endif {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, 0x01}}, {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, 0x00}}, -#if 0 - {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, /* 0x05 */ - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, -#endif {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, /* 0x05 - corrected 640x480-60 */ 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, 0x00}}, -#if 0 - {{0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e, /* 0x06 */ - 0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01, - 0x00}}, -#endif {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, /* 0x06 - corrected 640x480-72 */ 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, 0x00}}, @@ -359,19 +308,9 @@ static const SiS_CRT1TableStruct SiS300_CRT1Table[] = {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, 0x00}}, -#if 0 - {{0x66,0x4f,0x4f,0x86,0x56,0x9e,0x03,0x3e, /* 0x09 */ - 0xe4,0x87,0xdf,0xdf,0x04,0x00,0x00,0x01, - 0x00}}, -#endif {{0x67,0x4f,0x4f,0x8b,0x57,0x83,0x10,0x3e, /* 0x09 - corrected 640x480-100 */ 0xe7,0x8d,0xdf,0xe6,0x11,0x00,0x00,0x05, 0x00}}, -#if 0 - {{0x6c,0x4f,0x4f,0x83,0x59,0x9e,0x00,0x3e, /* 0x0a */ - 0xe5,0x8d,0xdf,0xdf,0x01,0x00,0x00,0x01, - 0x00}}, -#endif {{0x67,0x4f,0x4f,0x8b,0x57,0x83,0x10,0x3e, /* 0x0a - corrected 640x480-120 */ 0xe7,0x8d,0xdf,0xe6,0x11,0x00,0x00,0x05, 0x00}}, @@ -459,11 +398,6 @@ static const SiS_CRT1TableStruct SiS300_CRT1Table[] = {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, 0x00}}, -#if 0 - {{0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef, /* 0x27: 1280x960-70 - invalid! */ - 0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07, - 0x01}}, -#endif {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, /* 0x27: 1280x960-60 - correct */ 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, 0x01}}, @@ -497,9 +431,9 @@ static const SiS_CRT1TableStruct SiS300_CRT1Table[] = {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, 0x00}}, - {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0, /* 0x32 */ - 0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05, - 0x01}}, + {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0, /* 0x32: 720x576, corrected to 60Hz */ + 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, + 0x41}}, {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, /* 0x33 - 1024x600 */ 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, 0x01}}, @@ -560,18 +494,24 @@ static const SiS_CRT1TableStruct SiS300_CRT1Table[] = {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5, /* 1280x768-60 */ 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07, 0x01}}, /* 0x46 */ - {{0x7b,0x5f,0x63,0x9f,0x6a,0x93,0x6f,0xf0, /* 768x576 */ - 0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05, - 0x01}}, /* 0x47 */ + {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0, /* 768x576, corrected to 60Hz */ + 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, + 0x41}}, /* 0x47 */ {{0xce,0xa9,0xa9,0x92,0xb1,0x07,0x28,0x52, /* 1360x1024 (Barco iQ Pro R300) */ 0x02,0x8e,0xff,0x00,0x29,0x0d,0x00,0x03, 0x00}}, /* 0x48 */ {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, /* 1152x864-60 */ 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, - 0x41}} /* 0x49 */ + 0x41}}, /* 0x49 */ + {{0x5c,0x4f,0x4f,0x80,0x57,0x80,0xa3,0x1f, /* fake 640x400@60Hz (for LCD and TV, not actually used) */ + 0x98,0x8c,0x8f,0x96,0xa4,0x30,0x00,0x05, + 0x40}}, /* 0x4a */ + {{0x2c,0x27,0x27,0x90,0x2d,0x92,0xa4,0x1f, /* fake 320x200@60Hz (for LCD and TV, not actually used) */ + 0x98,0x8c,0x8f,0x96,0xa5,0x30,0x00,0x04, + 0x00}} /* 0x4b */ }; -static const SiS_MCLKDataStruct SiS300_MCLKData_630[] = +static const struct SiS_MCLKData SiS300_MCLKData_630[] = { { 0x5a,0x64,0x80, 66}, { 0xb3,0x45,0x80, 83}, @@ -583,7 +523,7 @@ static const SiS_MCLKDataStruct SiS300_MCLKData_630[] = { 0x37,0x61,0x80,100} }; -static const SiS_MCLKDataStruct SiS300_MCLKData_300[] = +static const struct SiS_MCLKData SiS300_MCLKData_300[] = { { 0x68,0x43,0x80,125}, { 0x68,0x43,0x80,125}, @@ -595,7 +535,7 @@ static const SiS_MCLKDataStruct SiS300_MCLKData_300[] = { 0x37,0x61,0x80,100} }; -static SiS_VCLKDataStruct SiS300_VCLKData[] = +static struct SiS_VCLKData SiS300_VCLKData[] = { { 0x1b,0xe1, 25}, /* 0x00 */ { 0x4e,0xe4, 28}, /* 0x01 */ @@ -669,53 +609,26 @@ static SiS_VCLKDataStruct SiS300_VCLKData[] = { 0xe2,0x46,135}, /* 0x45 */ /* 1280x1024-75, better clock for VGA2 */ { 0x70,0x29, 81}, /* 0x46 */ /* unused */ { 0, 0, 0}, /* 0x47 custom (will be filled out) */ - { 0xce,0x25,189} /* 0x48 */ /* Replacement for index 0x1b for 730 (and 540?) */ + { 0xce,0x25,189}, /* 0x48 */ /* Replacement for index 0x1b for 730 (and 540?) */ + { 0x15,0xe1, 20}, /* 0x49 */ /* 640x400@60 (fake, not actually used) */ + { 0x5f,0xc6, 33}, /* 0x4a */ /* 720x576@60 */ + { 0x37,0x5a, 10}, /* 0x4b */ /* 320x200@60 (fake, not actually used) */ + { 0x2b,0xc2, 35} /* 0x4c */ /* 768@576@60 */ }; -#ifdef LINUX_KERNEL -static UCHAR SiS300_SR07 = 0x10; -#endif - -static const DRAM4Type SiS300_SR15[8] = +static const unsigned char SiS300_SR15[4 * 8] = { - {0x01,0x09,0xa3,0x00}, - {0x43,0x43,0x43,0x00}, - {0x1e,0x1e,0x1e,0x00}, - {0x2a,0x2a,0x2a,0x00}, - {0x06,0x06,0x06,0x00}, - {0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00}, - {0x00,0x00,0x00,0x00} + 0x01,0x09,0xa3,0x00, + 0x43,0x43,0x43,0x00, + 0x1e,0x1e,0x1e,0x00, + 0x2a,0x2a,0x2a,0x00, + 0x06,0x06,0x06,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 }; -#ifdef LINUX_KERNEL -static UCHAR SiS300_SR1F = 0x00; -static UCHAR SiS300_SR21 = 0x16; -static UCHAR SiS300_SR22 = 0xb2; -static UCHAR SiS300_SR23 = 0xf6; -static UCHAR SiS300_SR24 = 0x0d; -static UCHAR SiS300_SR25[] = {0x0,0x0}; -static UCHAR SiS300_SR31 = 0x00; -static UCHAR SiS300_SR32 = 0x11; -static UCHAR SiS300_SR33 = 0x00; -static UCHAR SiS300_CRT2Data_1_2 = 0x40; -static UCHAR SiS300_CRT2Data_4_D = 0x00; -static UCHAR SiS300_CRT2Data_4_E = 0x00; -static UCHAR SiS300_CRT2Data_4_10 = 0x80; - -static const USHORT SiS300_RGBSenseData = 0xd1; -static const USHORT SiS300_VideoSenseData = 0xb3; -static const USHORT SiS300_YCSenseData = 0xb9; -static const USHORT SiS300_RGBSenseData2 = 0x0190; -static const USHORT SiS300_VideoSenseData2 = 0x0174; -static const USHORT SiS300_YCSenseData2 = 0x016b; - -static const DRAM4Type SiS300_CR40[5]; - -static UCHAR SiS300_CR49[2]; -#endif - -static const SiS_PanelDelayTblStruct SiS300_PanelDelayTbl[] = +static const struct SiS_PanelDelayTbl SiS300_PanelDelayTbl[] = { {{0x05,0xaa}}, {{0x05,0x14}}, @@ -735,33 +648,11 @@ static const SiS_PanelDelayTblStruct SiS300_PanelDelayTbl[] = {{0x05,0x60}} }; -#if 0 -static const SiS_PanelDelayTblStruct SiS300_PanelDelayTblLVDS[] = -{ - {{0x05,0xaa}}, - {{0x05,0x14}}, - {{0x05,0x36}}, - {{0x05,0x14}}, - {{0x05,0x14}}, - {{0x05,0x14}}, - {{0x05,0x90}}, - {{0x05,0x90}}, - {{0x05,0x14}}, - {{0x05,0x14}}, - {{0x05,0x14}}, - {{0x05,0x14}}, /* 2.07a (JVC): 14,96 */ - {{0x05,0x28}}, /* 2.04.5c: 20, 80 - Clevo (2.04.2c): 05, 28 */ - {{0x05,0x14}}, - {{0x05,0x14}}, /* Some BIOSes: 05, 40 */ - {{0x05,0x60}} -}; -#endif - /**************************************************************/ /* SIS VIDEO BRIDGE ----------------------------------------- */ /**************************************************************/ -static const SiS_LCDDataStruct SiS300_St2LCD1024x768Data[] = +static const struct SiS_LCDData SiS300_St2LCD1024x768Data[] = { { 62, 25, 800, 546,1344, 806}, { 32, 15, 930, 546,1344, 806}, @@ -772,7 +663,7 @@ static const SiS_LCDDataStruct SiS300_St2LCD1024x768Data[] = { 1, 1,1344, 806,1344, 806} }; -static const SiS_LCDDataStruct SiS300_ExtLCD1024x768Data[] = +static const struct SiS_LCDData SiS300_ExtLCD1024x768Data[] = { { 12, 5, 896, 512,1344, 806}, { 12, 5, 896, 510,1344, 806}, @@ -789,7 +680,7 @@ static const SiS_LCDDataStruct SiS300_ExtLCD1024x768Data[] = { 1, 1,1344, 806,1344, 806} }; -static const SiS_LCDDataStruct SiS300_St2LCD1280x1024Data[] = +static const struct SiS_LCDData SiS300_St2LCD1280x1024Data[] = { { 22, 5, 800, 510,1650,1088}, { 22, 5, 800, 510,1650,1088}, @@ -801,7 +692,7 @@ static const SiS_LCDDataStruct SiS300_St2LCD1280x1024Data[] = { 1, 1,1688,1066,1688,1066} }; -static const SiS_LCDDataStruct SiS300_ExtLCD1280x1024Data[] = +static const struct SiS_LCDData SiS300_ExtLCD1280x1024Data[] = { { 211, 60,1024, 501,1688,1066}, { 211, 60,1024, 508,1688,1066}, @@ -813,53 +704,116 @@ static const SiS_LCDDataStruct SiS300_ExtLCD1280x1024Data[] = { 1, 1,1688,1066,1688,1066} }; -static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_1[] = +static const struct SiS_Part2PortTbl SiS300_CRT2Part2_1024x768_1[] = { /* VESA Timing */ - {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, - {{0x2c,0x12,0x9a,0xae,0x88,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, - {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, - {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, - {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}} + {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}} }; -static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_2[] = +static const struct SiS_Part2PortTbl SiS300_CRT2Part2_1024x768_2[] = { /* Non-VESA */ - {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, - {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, - {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, - {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, - {{0x28,0x13,0xe7,0x0b,0xe8,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, - {{0x38,0x18,0x16,0x00,0x00,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, - {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}} -}; - -static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_3[] = -{ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} -}; - -static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_1[] = -{ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} -}; - -static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_2[] = -{ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} + {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x28,0x13,0xe7,0x0b,0xe8,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x38,0x18,0x16,0x00,0x00,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}} }; -static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_3[] = +static const struct SiS_Part2PortTbl SiS300_CRT2Part2_1024x768_3[] = { - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} }; /**************************************************************/ /* LVDS/Chrontel -------------------------------------------- */ /**************************************************************/ -static const SiS_LVDSDataStruct SiS300_CHTVUPALData[] = +/* Custom data for Barco iQ R series */ +static const struct SiS_LVDSData SiS300_LVDSBARCO1366Data_1[]= +{ + { 832, 438,1331, 806}, + { 832, 388,1331, 806}, + { 832, 438,1331, 806}, + { 832, 388,1331, 806}, + { 832, 518,1331, 806}, + {1050, 638,1344, 806}, + {1344, 806,1344, 806}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066} /* 1360x1024 */ +}; + +/* Custom data for Barco iQ R series */ +static const struct SiS_LVDSData SiS300_LVDSBARCO1366Data_2[]= +{ + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1344, 806,1344, 806}, + {1688,1066,1688,1066}, + {1688,1066,1688,1066} /* 1360x1024 */ +}; + +/* Custom data for Barco iQ G series */ +static const struct SiS_LVDSData SiS300_LVDSBARCO1024Data_1[]= +{ + { 832, 438,1331, 806}, + { 832, 409,1331, 806}, + { 832, 438,1331, 806}, + { 832, 409,1331, 806}, + { 832, 518,1331, 806}, /* 640x480 */ + {1050, 638,1344, 806}, /* 800x600 */ + {1344, 806,1344, 806}, /* 1024x768 */ +}; + +/* Custom data for 848x480 and 856x480 parallel LVDS panels */ +static const struct SiS_LVDSData SiS300_LVDS848x480Data_1[]= +{ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 640x480 TODO */ + {1088, 525,1088, 525}, /* 800x600 TODO */ + {1088, 525,1088, 525}, /* 1024x768 TODO */ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 848x480 */ + {1088, 525,1088, 525}, /* 856x480 */ + {1088, 525,1088, 525} /* 1360x768 TODO */ +}; + +/* Custom data for 848x480 parallel panel */ +static const struct SiS_LVDSData SiS300_LVDS848x480Data_2[]= +{ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 640x480 */ + {1088, 525,1088, 525}, /* 800x600 */ + {1088, 525,1088, 525}, /* 1024x768 */ + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + { 0, 0, 0, 0}, + {1088, 525,1088, 525}, /* 848x480 */ + {1088, 525,1088, 525}, /* 856x480 */ + {1088, 525,1088, 525} /* 1360x768 TODO */ +}; + +static const struct SiS_LVDSData SiS300_CHTVUPALData[] = { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -869,7 +823,7 @@ static const SiS_LVDSDataStruct SiS300_CHTVUPALData[] = { 936, 836, 936, 836} }; -static const SiS_LVDSDataStruct SiS300_CHTVOPALData[] = +static const struct SiS_LVDSData SiS300_CHTVOPALData[] = { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -879,7 +833,7 @@ static const SiS_LVDSDataStruct SiS300_CHTVOPALData[] = { 960, 750, 960, 750} }; -static const SiS_LVDSDataStruct SiS300_CHTVSOPALData[] = +static const struct SiS_LVDSData SiS300_CHTVSOPALData[] = { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -889,486 +843,8 @@ static const SiS_LVDSDataStruct SiS300_CHTVSOPALData[] = { 944, 625, 944, 625} }; - -static const SiS_LVDSDesStruct SiS300_PanelType00_1[] = -{ - { 1059, 626 }, /* 2.08 */ - { 1059, 624 }, - { 1059, 626 }, - { 1059, 624 }, - { 1059, 624 }, - { 0, 627 }, - { 0, 627 }, - { 0, 0 }, - { 0, 0 } -#if 0 - {0, 626}, - {0, 624}, - {0, 626}, - {0, 624}, - {0, 624}, - {0, 627}, - {0, 627}, - {0, 0}, - {0, 0} -#endif -}; - -static const SiS_LVDSDesStruct SiS300_PanelType01_1[] = -{ - { 0, 0 }, /* 2.08 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 } -#if 0 - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -#endif -}; - -static const SiS_LVDSDesStruct SiS300_PanelType02_1[] = -{ - { 1059, 626 }, /* 2.08 */ - { 1059, 624 }, - { 1059, 626 }, - { 1059, 624 }, - { 1059, 624 }, - { 0, 627 }, - { 0, 627 }, - { 0, 0 }, - { 0, 0 } -#if 0 - {0, 626}, - {0, 624}, - {0, 626}, - {0, 624}, - {0, 624}, - {0, 627}, - {0, 627}, - {0, 0}, - {0, 0} -#endif -}; - -static const SiS_LVDSDesStruct SiS300_PanelType03_1[] = -{ - { 8, 436}, - { 8, 440}, - { 8, 436}, - { 8, 440}, - { 8, 512}, - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType04_1[] = /* 1280x1024 */ -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType05_1[] = -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType06_1[] = /* Clevo Trumpion 1024x768 */ -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType07_1[] = -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType08_1[] = -{ - {1059, 626}, - {1059, 624}, - {1059, 626}, - {1059, 624}, - {1059, 624}, - { 0, 627}, - { 0, 627}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType09_1[] = -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0a_1[] = -{ - {1059, 626}, - {1059, 624}, - {1059, 626}, - {1059, 624}, - {1059, 624}, - { 0, 627}, - { 0, 627}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0b_1[] = -{ - {1343, 0}, - {1343, 0}, - {1343, 0}, - {1343, 0}, - {1343, 0}, - {1343, 0}, - { 0, 799}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0c_1[] = -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0d_1[] = -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0e_1[] = -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, /* 640x480 */ - {1343, 0}, /* 800x600 */ - { 0, 805}, /* 1024x768 */ - { 0, 794}, /* 1280x1024 */ - { 0, 0} /* 1280x960 - not applicable */ -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0f_1[] = -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType00_2[] = -{ - {976, 527}, - {976, 502}, - {976, 527}, - {976, 502}, - {976, 567}, - { 0, 627}, - { 0, 627}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType01_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType02_2[] = -{ - {976, 527}, - {976, 502}, - {976, 527}, - {976, 502}, - {976, 567}, - { 0, 627}, - { 0, 627}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType03_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - {1152, 622}, - {1152, 597} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType04_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType05_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType06_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType07_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType08_2[] = -{ - {976, 527}, - {976, 502}, - {976, 527}, - {976, 502}, - {976, 567}, - { 0, 627}, - { 0, 627}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType09_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0a_2[] = -{ - {976, 527}, - {976, 502}, - {976, 527}, - {976, 502}, - {976, 567}, - { 0, 627}, - { 0, 627}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0b_2[] = -{ - { 1152, 700}, - { 1152, 675}, - { 1152, 700}, - { 1152, 675}, - { 1152, 740}, - { 1232, 799}, - { 0, 799}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0c_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0d_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0e_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelType0f_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelTypeNS_1[]= -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 805}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS300_PanelTypeNS_2[] = -{ - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0} -}; - -/* Custom data for Barco iQ R200/300/400 (BIOS 2.00.07) */ -static const SiS_LVDSDesStruct SiS300_PanelType04_1a[] = /* 1280x1024 (1366x1024) */ +/* Custom des data for Barco iQ R200/300/400 (BIOS 2.00.07) */ +static const struct SiS_LVDSDes SiS300_PanelType04_1a[] = /* 1280x1024 (1366x1024) */ { {1330, 798}, /* 320x200 */ {1330, 794}, @@ -1381,7 +857,7 @@ static const SiS_LVDSDesStruct SiS300_PanelType04_1a[] = /* 1280x1024 (1366x102 { 0, 0} /* 1360x1024 */ }; -static const SiS_LVDSDesStruct SiS300_PanelType04_2a[] = +static const struct SiS_LVDSDes SiS300_PanelType04_2a[] = { {1152, 622}, {1152, 597}, @@ -1394,8 +870,8 @@ static const SiS_LVDSDesStruct SiS300_PanelType04_2a[] = { 0, 0} }; -/* Custom data for Barco iQ G200/300/400 (BIOS 2.00.07) */ -static const SiS_LVDSDesStruct SiS300_PanelType04_1b[] = /* 1024x768 */ +/* Custom des data for Barco iQ G200/300/400 (BIOS 2.00.07) */ +static const struct SiS_LVDSDes SiS300_PanelType04_1b[] = /* 1024x768 */ { {1330, 798}, /* 320x200 */ {1330, 794}, @@ -1406,7 +882,7 @@ static const SiS_LVDSDesStruct SiS300_PanelType04_1b[] = /* 1024x768 */ { 0, 805} /* 1024x768 / 512x384 */ }; -static const SiS_LVDSDesStruct SiS300_PanelType04_2b[] = +static const struct SiS_LVDSDes SiS300_PanelType04_2b[] = { {1152, 622}, {1152, 597}, @@ -1419,376 +895,7 @@ static const SiS_LVDSDesStruct SiS300_PanelType04_2b[] = /* CRT1 CRTC for slave modes */ -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1[] = -{ - {{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f, - 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, - 0x00 }}, - {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, - 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, - 0x00 }}, - {{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f, - 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, - 0x00 }}, - {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f, - 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, - 0x00 }}, - {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e, - 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, - 0x00 }}, - {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1_H[] = -{ - {{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f, - 0x90,0x85,0x8f,0xab,0x30,0x00,0x04, - 0x00 }}, - {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f, - 0x5e,0x83,0x5d,0x79,0x10,0x00,0x04, - 0x00 }}, - {{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f, - 0x90,0x85,0x8f,0xab,0x30,0x00,0x04, - 0x00 }}, - {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f, - 0x5e,0x83,0x5d,0x79,0x10,0x00,0x04, - 0x00 }}, - {{0x30,0x27,0x94,0x2c,0x92,0x04,0x3e, - 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x04, - 0x00 }}, - {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x05, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1[] = -{ - {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0x04,0x3e, - 0xe2,0x89,0xdf,0x05,0x00,0x00,0x01, - 0x00}}, - {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0, - 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26, - 0x01}}, - {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x02, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1_H[] = -{ - {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, - 0x00 }}, - {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, - 0x60,0x87,0x5D,0x83,0x10,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, - 0x60,0x87,0x5D,0x83,0x10,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e, - 0xE2,0x89,0xdf,0x05,0x00,0x00,0x44, - 0x00}}, - {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0, - 0x5A,0x8F,0x57,0x7D,0x20,0x00,0x55, - 0x01}}, - {{0x4f,0x3F,0x93,0x45,0x0D,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01 }} - -#if 0 - {{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, - 0x00 }}, - {{0x37,0x27,0x9B,0x2b,0x94,0x97,0x1f, - 0x60,0x87,0x5D,0x83,0x01,0x00,0x44, - 0x00}}, - {{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, - 0x00}}, - {{0x37,0x27,0x9B,0x2b,0x94,0x97,0x1f, - 0x60,0x87,0x5D,0x83,0x01,0x00,0x44, - 0x00}}, - {{0x37,0x27,0x9B,0x2b,0x94,0x04,0x3e, - 0xE2,0x89,0xDf,0x05,0x00,0x00,0x44, - 0x00}}, - {{0x41,0x31,0x85,0x35,0x1d,0x7c,0xf0, - 0x5A,0x8F,0x57,0x7D,0x20,0x00,0x55, - 0x01}}, - {{0x4f,0x3F,0x93,0x45,0x0D,0x24,0xf5, - 0x02,0x88,0xFf,0x25,0x10,0x00,0x01, - 0x01 }} -#endif -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1[] = -{ - {{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, - 0x00 }}, - {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, - 0x00 }}, - {{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, - 0x00 }}, - {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, - 0x00 }}, - {{0x63,0x4f,0x87,0x54,0x9f,0x04,0x3e, - 0xe2,0x89,0xdf,0x05,0x00,0x00,0x01, - 0x00 }}, - {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0, - 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26, - 0x01 }}, - {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x02, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1_H[] = -{ - {{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x04, - 0x00 }}, - {{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x04, - 0x00 }}, - {{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x04, - 0x00 }}, - {{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x04, - 0x00 }}, - {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e, - 0xe2,0x89,0xdf,0x05,0x00,0x00,0x04, - 0x00 }}, - {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0, - 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55, - 0x01 }}, - {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2[] = -{ - {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, - 0xf4,0x88,0x8f,0x73,0x20,0x00,0x06, - 0x00 }}, - {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, - 0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06, - 0x00 }}, - {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, - 0xf4,0x88,0x8f,0x73,0x20,0x00,0x06, - 0x00 }}, - {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, - 0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06, - 0x00 }}, - {{0x7f,0x4f,0x83,0x62,0x12,0x72,0xba, - 0x1c,0x80,0xdf,0x73,0x00,0x00,0x06, - 0x00 }}, - {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2_H[] = -{ - {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e, - 0xf4,0x88,0x8f,0x73,0x20,0x00,0x05, - 0x00 }}, - {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e, - 0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05, - 0x00 }}, - {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e, - 0xf4,0x88,0x8f,0x73,0x20,0x00,0x05, - 0x00 }}, - {{0x3d,0x27,0x81,0x3a,0x1a,0x72,0x3e, - 0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05, - 0x00 }}, - {{0x3d,0x27,0x81,0x32,0x1a,0x72,0xba, - 0x1c,0x80,0xdf,0x73,0x00,0x00,0x05, - 0x00 }}, - {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x05, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2[] = -{ - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x72,0x88,0xdf,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1, - 0xae,0x84,0x57,0x25,0x30,0x00,0x02, - 0x01 }}, - {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x02, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2_H[] = -{ - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x72,0x88,0xdf,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1, - 0xae,0x84,0x57,0x25,0x30,0x00,0x01, - 0x01 }}, - {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2[] = -{ - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x72,0x88,0xdf,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1, - 0xae,0x84,0x57,0x25,0x30,0x00,0x02, - 0x01 }}, - {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x02, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2_H[] = -{ - {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, - 0x72,0x88,0xdf,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x31,0x93,0x3e,0x86,0x24,0xf1, - 0xae,0x84,0x57,0x25,0x30,0x00,0x01, - 0x01 }}, - {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1XXXxXXX_1[] = -{ - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, - {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, - 0x01}}, - {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x02, - 0x01}}, - {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, - 0x00,0x84,0xff,0x29,0x09,0x00,0x07, - 0x01}}, - {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x07, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1XXXxXXX_1_H[] = -{ - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, - {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x01, - 0x01}}, - {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01}} -}; - - -static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1UNTSC[] = +static const struct SiS_LVDSCRT1Data SiS300_CHTVCRT1UNTSC[] = { {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, @@ -1810,7 +917,7 @@ static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1UNTSC[] = 0x01 }} }; -static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1ONTSC[] = +static const struct SiS_LVDSCRT1Data SiS300_CHTVCRT1ONTSC[] = { {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, @@ -1832,7 +939,7 @@ static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1ONTSC[] = 0x01 }} }; -static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1UPAL[] = +static const struct SiS_LVDSCRT1Data SiS300_CHTVCRT1UPAL[] = { {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, @@ -1854,7 +961,7 @@ static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1UPAL[] = 0x01 }} }; -static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1OPAL[] = +static const struct SiS_LVDSCRT1Data SiS300_CHTVCRT1OPAL[] = { {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, @@ -1876,7 +983,7 @@ static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1OPAL[] = 0x01 }} }; -static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1SOPAL[] = +static const struct SiS_LVDSCRT1Data SiS300_CHTVCRT1SOPAL[] = { {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, @@ -1898,7 +1005,7 @@ static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1SOPAL[] = 0x01 }} }; -static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = +static const struct SiS_CHTVRegData SiS300_CHTVReg_UNTSC[] = { {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, @@ -1908,7 +1015,7 @@ static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = {{0x8d,0xc4,0x00,0x3b,0xfb,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 24: 800x600 NTSC 7/10 */ }; -static const SiS_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = +static const struct SiS_CHTVRegData SiS300_CHTVReg_ONTSC[] = { {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, @@ -1918,7 +1025,7 @@ static const SiS_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = {{0x8c,0xb4,0x00,0x32,0xf9,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 23: 800x600 NTSC 3/4 */ }; -static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = +static const struct SiS_CHTVRegData SiS300_CHTVReg_UPAL[] = { {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, @@ -1929,7 +1036,7 @@ static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = }; -static const SiS_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = +static const struct SiS_CHTVRegData SiS300_CHTVReg_OPAL[] = { {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */ {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, @@ -1940,26 +1047,26 @@ static const SiS_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = }; -static const SiS_CHTVRegDataStruct SiS300_CHTVReg_SOPAL[] = +static const struct SiS_CHTVRegData SiS300_CHTVReg_SOPAL[] = { {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */ {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, - {{0x60,0x30,0x00,0x10,0x00,0,0,0,0,0,0,0,0,0,0,0}}, /* TW: Mode 13: 640x480 PAL 5/4 */ - {{0x81,0x50,0x00,0x1b,0x00,0,0,0,0,0,0,0,0,0,0,0}} /* TW: Mode 19: 800x600 PAL 1/1 */ + {{0x60,0x30,0x00,0x10,0x00,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 13: 640x480 PAL 5/4 */ + {{0x81,0x50,0x00,0x1b,0x00,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 19: 800x600 PAL 1/1 */ }; -static const UCHAR SiS300_CHTVVCLKUNTSC[] = {0x29,0x29,0x29,0x29,0x2a,0x2e}; +static const unsigned char SiS300_CHTVVCLKUNTSC[] = { 0x29,0x29,0x29,0x29,0x2a,0x2e }; -static const UCHAR SiS300_CHTVVCLKONTSC[] = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b}; +static const unsigned char SiS300_CHTVVCLKONTSC[] = { 0x2c,0x2c,0x2c,0x2c,0x2d,0x2b }; -static const UCHAR SiS300_CHTVVCLKSONTSC[] = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b}; +static const unsigned char SiS300_CHTVVCLKSONTSC[] = { 0x2c,0x2c,0x2c,0x2c,0x2d,0x2b }; -static const UCHAR SiS300_CHTVVCLKUPAL[] = {0x2f,0x2f,0x2f,0x2f,0x2f,0x31}; +static const unsigned char SiS300_CHTVVCLKUPAL[] = { 0x2f,0x2f,0x2f,0x2f,0x2f,0x31 }; -static const UCHAR SiS300_CHTVVCLKOPAL[] = {0x2f,0x2f,0x2f,0x2f,0x30,0x32}; +static const unsigned char SiS300_CHTVVCLKOPAL[] = { 0x2f,0x2f,0x2f,0x2f,0x30,0x32 }; -static const UCHAR SiS300_CHTVVCLKSOPAL[] = {0x2f,0x2f,0x2f,0x2f,0x36,0x29}; +static const unsigned char SiS300_CHTVVCLKSOPAL[] = { 0x2f,0x2f,0x2f,0x2f,0x36,0x29 }; diff --git a/drivers/video/sis/310vtbl.h b/drivers/video/sis/310vtbl.h index 2c71d048f7c40..54fcbbf4ef635 100644 --- a/drivers/video/sis/310vtbl.h +++ b/drivers/video/sis/310vtbl.h @@ -1,9 +1,9 @@ /* $XFree86$ */ /* $XdotOrg$ */ /* - * Register settings for SiS 315/330 series + * Register settings for SiS 315/330/340 series * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -50,37 +50,13 @@ * */ -static const SiS_StStruct SiS310_SModeIDTable[]= -{ - {0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00, 0x40}, - {0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00, 0x40}, - {0x01,0x1010,0x17,0x02,0x02,0x00,0x01,0x01, 0x40}, - {0x03,0x8208,0x03,0x00,0x00,0x00,0x01,0x02, 0x40}, - {0x03,0x0210,0x16,0x01,0x01,0x00,0x01,0x02, 0x40}, - {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03, 0x40}, - {0x05,0x9209,0x05,0x00,0x00,0x00,0x00,0x04, 0x40}, - {0x06,0x8209,0x06,0x00,0x00,0x00,0x00,0x05, 0x40}, - {0x07,0x0000,0x07,0x03,0x03,0x00,0x01,0x03, 0x40}, - {0x07,0x0000,0x19,0x02,0x02,0x00,0x01,0x03, 0x40}, - {0x0d,0x920a,0x0d,0x00,0x00,0x00,0x00,0x04, 0x40}, - {0x0e,0x820a,0x0e,0x00,0x00,0x00,0x00,0x05, 0x40}, - {0x0f,0x0202,0x11,0x01,0x01,0x00,0x00,0x05, 0x40}, - {0x10,0x0212,0x12,0x01,0x01,0x00,0x00,0x05, 0x40}, - {0x11,0x0212,0x1a,0x04,0x04,0x00,0x00,0x05, 0x40}, - {0x12,0x0212,0x1b,0x04,0x04,0x00,0x00,0x05, 0x40}, - {0x13,0x021b,0x1c,0x00,0x00,0x00,0x00,0x04, 0x40}, - {0x12,0x0010,0x18,0x02,0x02,0x00,0x00,0x05, 0x40}, - {0x12,0x0210,0x18,0x01,0x01,0x00,0x00,0x05, 0x40}, - {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00, 0x40} -}; - -static const SiS_ExtStruct SiS310_EModeIDTable[]= +static const struct SiS_Ext SiS310_EModeIDTable[] = { {0x6a,0x2212,0x0102,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x? */ {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */ - {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */ + {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */ {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */ - {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */ + {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */ {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */ {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */ {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */ @@ -103,10 +79,10 @@ static const SiS_ExtStruct SiS310_EModeIDTable[]= {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x16 */ {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x8 */ {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x8 */ - {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x8 */ + {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x8 */ {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x16 */ {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x16 */ - {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x16 */ + {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x16 */ {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x8 */ {0x5a,0x021b,0x0138,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x3f, 2}, /* 320x240x8 fstn */ {0x5b,0x0a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x3f, 2}, /* 320x240x16 fstn */ @@ -139,406 +115,335 @@ static const SiS_ExtStruct SiS310_EModeIDTable[]= {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x8 */ {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x16 */ {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x32 */ - {0x26,0x0e3b,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x8 */ - {0x27,0x0e7d,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x16 */ - {0x28,0x0eff,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x32*/ - {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1}, /* 1152x864 */ - {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1}, - {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1}, - {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x46,-1}, /* 848x480 */ - {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x46,-1}, - {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x46,-1}, - {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x48,-1}, /* 856x480 */ - {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x48,-1}, - {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x48,-1}, - {0x48,0x6a3b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4a,-1}, /* 1360x768 */ - {0x4b,0x6a7d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4a,-1}, - {0x4e,0x6aff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4a,-1}, + {0x26,0x0e3b,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x43, 9}, /* 1400x1050x8 */ + {0x27,0x0e7d,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x43, 9}, /* 1400x1050x16 */ + {0x28,0x0eff,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x43, 9}, /* 1400x1050x32*/ + {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x45,-1}, /* 1152x864 */ + {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x45,-1}, + {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x45,-1}, + {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x48,-1}, /* 848x480 */ + {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x48,-1}, + {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x48,-1}, + {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x4a,-1}, /* 856x480 */ + {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x4a,-1}, + {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x4a,-1}, + {0x48,0x6a3b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4c,-1}, /* 1360x768 */ + {0x4b,0x6a7d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4c,-1}, + {0x4e,0x6aff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x4c,-1}, {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x32 */ {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x32 */ {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x32 */ - {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4b,-1}, /* 768x576 */ - {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4b,-1}, - {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4b,-1}, - {0x14,0x0e3b,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4c, 7}, /* 1280x800 */ - {0x15,0x0e7d,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4c, 7}, - {0x16,0x0eff,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4c, 7}, - {0x17,0x0e3b,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4d, 9}, /* 1680x1050 */ - {0x18,0x0e7d,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4d, 9}, - {0x19,0x0eff,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4d, 9}, - {0x2c,0x267b,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4e,-1}, /* 1920x1080(i) */ - {0x2d,0x26fd,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4e,-1}, - {0x73,0x27ff,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4e,-1}, - {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x4f,-1}, /* 960x540 */ - {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x4f,-1}, - {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x4f,-1}, - {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x50,-1}, /* 960x600 */ - {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x50,-1}, - {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x50,-1}, + {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4d,-1}, /* 768x576 */ + {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4d,-1}, + {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4d,-1}, + {0x14,0x0e3b,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4e, 7}, /* 1280x800 */ + {0x15,0x0e7d,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4e, 7}, + {0x16,0x0eff,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4e, 7}, + {0x17,0x0e3b,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x51, 9}, /* 1680x1050 */ + {0x18,0x0e7d,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x51, 9}, + {0x19,0x0eff,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x51, 9}, + {0x2c,0x267b,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x52,-1}, /* 1920x1080(i) */ + {0x2d,0x26fd,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x52,-1}, + {0x73,0x27ff,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x52,-1}, + {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x53,-1}, /* 960x540 */ + {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x53,-1}, + {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x53,-1}, + {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x54,-1}, /* 960x600 */ + {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x54,-1}, + {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x54,-1}, + {0x1a,0x0e3b,0x0000,SIS_RI_1280x854, 0x00,0x00,0x00,0x00,0x55, 8}, /* 1280x854 */ + {0x1b,0x0e7d,0x0000,SIS_RI_1280x854, 0x00,0x00,0x00,0x00,0x55, 8}, + {0x1c,0x0eff,0x0000,SIS_RI_1280x854, 0x00,0x00,0x00,0x00,0x55, 8}, {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1} }; -static const SiS_Ext2Struct SiS310_RefIndex[]= -{ - {0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0x40}, /* 0x0 */ - {0x0067,0x0e,0x04,0x05,0x05,0x6a, 800, 600, 0x40}, /* 0x1 */ - {0x0067,0x0f,0x08,0x48,0x05,0x6a, 800, 600, 0x40}, /* 0x2 */ - {0x0067,0x10,0x07,0x8b,0x05,0x6a, 800, 600, 0x40}, /* 0x3 */ - {0x0047,0x11,0x0a,0x00,0x05,0x6a, 800, 600, 0x40}, /* 0x4 */ - {0x0047,0x12,0x0d,0x00,0x05,0x6a, 800, 600, 0x40}, /* 0x5 */ - {0x0047,0x13,0x13,0x00,0x05,0x6a, 800, 600, 0x20}, /* 0x6 */ - {0x0107,0x14,0x1c,0x00,0x05,0x6a, 800, 600, 0x20}, /* 0x7 */ - {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40}, /* 0x8 */ - {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40}, /* 0x9 */ - {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40}, /* 0xa */ - {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40}, /* 0xb */ - {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xc */ - {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xd */ - {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xe */ - {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xf */ - {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30}, /* 0x10 */ - {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30}, /* 0x11 */ - {0x006f,0x3d,0x03,0x06,0x14,0x32, 720, 576, 0x30}, /* 0x12 */ - {0x0087,0x15,0x06,0x00,0x06,0x37,1024, 768, 0x30}, /* 0x13 */ - {0xc877,0x16,0x0b,0x06,0x06,0x37,1024, 768, 0x20}, /* 0x14 */ - {0xc067,0x17,0x0f,0x49,0x06,0x37,1024, 768, 0x20}, /* 0x15 */ - {0x0067,0x18,0x11,0x00,0x06,0x37,1024, 768, 0x20}, /* 0x16 */ - {0x0047,0x19,0x16,0x8c,0x06,0x37,1024, 768, 0x20}, /* 0x17 */ - {0x0107,0x1a,0x1b,0x00,0x06,0x37,1024, 768, 0x10}, /* 0x18 */ - {0x0107,0x1b,0x1f,0x00,0x06,0x37,1024, 768, 0x10}, /* 0x19 */ - {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30}, /* 0x1a */ - {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00}, /* 0x1b */ - {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00}, /* 0x1c */ - {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00}, /* 0x1d */ - {0x0227,0x20,0x21,0x09,0x09,0x3c,1600,1200, 0x00}, /* 0x1e */ - {0x0407,0x21,0x22,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x1f */ - {0x0407,0x22,0x23,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x20 */ - {0x0407,0x23,0x25,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x21 */ - {0x0007,0x24,0x26,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x22 */ - {0x0007,0x25,0x2c,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x23 */ - {0x0007,0x26,0x34,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x24 */ - {0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0x30}, /* 0x25 */ - {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30}, /* 0x26 */ - {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30}, /* 0x27 */ - {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30}, /* 0x28 */ - {0x8007,0x27,0x27,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x29 */ - {0x4007,0x28,0x29,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2a */ - {0x4007,0x29,0x2e,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2b */ - {0x4007,0x2a,0x30,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2c */ - {0x4007,0x2b,0x35,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2d */ - {0x4005,0x2c,0x39,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2e */ - {0x4007,0x2d,0x2b,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x2f */ - {0x4007,0x2e,0x31,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x30 */ - {0x4007,0x2f,0x33,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x31 */ - {0x4007,0x30,0x37,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x32 */ - {0x4005,0x31,0x38,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x33 */ - {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x34 */ - {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x35 */ - {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x36 */ - {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x37 */ - {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x38 */ - {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x39 */ - {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3a */ - {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3b */ - {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3c */ - {0x0127,0x3b,0x19,0x08,0x0a,0x7c,1280, 960, 0x30}, /* 0x3d */ - {0x0227,0x4c,0x59,0x08,0x0a,0x7c,1280, 960, 0x20}, /* 0x3e */ - {0xc07f,0x4e,0x00,0x06,0x04,0x5a, 320, 240, 0x30}, /* 0x3f */ /* FSTN 320x240 */ - {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30}, /* 0x40 */ /* 0x5b was 0x12 */ - {0x0127,0x43,0x4d,0x08,0x0b,0x26,1400,1050, 0x30}, /* 0x41 */ - {0x0207,0x4b,0x5a,0x08,0x0b,0x26,1400,1050, 0x30}, /* 0x42 1400x1050-75Hz */ - {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x43 1152x864-60Hz */ - {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x44 1152x864-75Hz */ - {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x45 1152x864-85Hz */ - {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30}, /* 0x46 848x480-38Hzi */ - {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30}, /* 0x47 848x480-60Hz */ - {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30}, /* 0x48 856x480-38Hzi */ - {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30}, /* 0x49 856x480-60Hz */ - {0x0067,0x49,0x58,0x0c,0x1b,0x48,1360, 768, 0x30}, /* 0x4a 1360x768-60Hz */ - {0x006f,0x4d,0x03,0x06,0x15,0x5f, 768, 576, 0x30}, /* 0x4b 768x576-56Hz */ - {0x0067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30}, /* 0x4c 1280x800-60Hz */ - {0x0067,0x50,0x5d,0x0c,0x0e,0x17,1680,1050, 0x30}, /* 0x4d 1680x1050-60Hz */ - {0x0087,0x51,0x69,0x00,0x00,0x2c,1920,1080, 0x30}, /* 0x4e 1920x1080 60Hzi */ - {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30}, /* 0x4f 960x540 60Hz */ - {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30}, /* 0x50 960x600 60Hz */ - {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0} -}; - -#ifdef LINUX_XF86 -static const struct { - UCHAR Ext_ModeID; /* ModeID in new ROM */ - UCHAR Ext_MyModeID; /* corresponding ModeID in my tables (0 = identical) */ - USHORT Ext_VESAID; /* corresponding VESA ID in new ROM */ -} SiS_EModeIDTable661[] = { - { 0x6a, 0x00, 0x0102 }, - { 0x1d, 0x20, 0x0000 }, - { 0x1e, 0x21, 0x0000 }, - { 0x1f, 0x22, 0x0000 }, - { 0x20, 0x29, 0x0000 }, - { 0x21, 0x2a, 0x0000 }, - { 0x22, 0x2b, 0x0000 }, - { 0x23, 0x00, 0x011c }, - { 0x24, 0x00, 0x011d }, - { 0x25, 0x00, 0x011e }, - { 0x26, 0x00, 0x011f }, - { 0x27, 0x00, 0x0120 }, - { 0x28, 0x00, 0x0121 }, - { 0x2a, 0x14, 0x013d }, - { 0x2b, 0x15, 0x013e }, - { 0x2c, 0x16, 0x013f }, - { 0x2e, 0x00, 0x0101 }, - { 0x2f, 0x00, 0x0100 }, - { 0x30, 0x00, 0x0103 }, - { 0x37, 0x00, 0x0104 }, - { 0x38, 0x00, 0x0105 }, - { 0x3a, 0x00, 0x0107 }, - { 0x3c, 0x00, 0x0125 }, - { 0x3d, 0x00, 0x0126 }, - { 0x40, 0x00, 0x010d }, - { 0x41, 0x00, 0x010e }, - { 0x43, 0x00, 0x0110 }, - { 0x44, 0x00, 0x0111 }, - { 0x46, 0x00, 0x0113 }, - { 0x47, 0x00, 0x0114 }, - { 0x49, 0x00, 0x0116 }, - { 0x4a, 0x00, 0x0117 }, - { 0x4c, 0x00, 0x0119 }, - { 0x4d, 0x00, 0x011a }, - { 0x50, 0x00, 0x0127 }, - { 0x51, 0x00, 0x0128 }, - { 0x52, 0x00, 0x0129 }, - { 0x56, 0x00, 0x012a }, - { 0x57, 0x00, 0x012b }, - { 0x58, 0x00, 0x012c }, - { 0x59, 0x00, 0x012d }, - { 0x5a, 0x17, 0x012e }, - { 0x5b, 0x18, 0x012f }, - { 0x5c, 0x19, 0x0130 }, - { 0x5d, 0x00, 0x0131 }, - { 0x62, 0x00, 0x0112 }, - { 0x63, 0x00, 0x0115 }, - { 0x64, 0x00, 0x0118 }, - { 0x65, 0x00, 0x011b }, - { 0x66, 0x00, 0x0132 }, - { 0x75, 0x00, 0x013a }, - { 0x78, 0x00, 0x013b }, - { 0x79, 0x00, 0x013c }, - { 0x7b, 0x7c, 0x0136 }, - { 0x7c, 0x7d, 0x0137 }, - { 0x7d, 0x7e, 0x0138 }, - { 0xff, 0xff, 0xffff } -}; -#endif - -static const SiS_CRT1TableStruct SiS310_CRT1Table[]= +static const struct SiS_Ext2 SiS310_RefIndex[] = +{ + {0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x0 */ + {0x0067,0x0e,0x04,0x05,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1 */ + {0x0067,0x0f,0x08,0x48,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2 */ + {0x0067,0x10,0x07,0x8b,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x3 */ + {0x0047,0x11,0x0a,0x00,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x4 */ + {0x0047,0x12,0x0d,0x00,0x05,0x6a, 800, 600, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x5 */ + {0x0047,0x13,0x13,0x00,0x05,0x6a, 800, 600, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x6 */ + {0x0107,0x14,0x1c,0x00,0x05,0x6a, 800, 600, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x7 */ + {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x8 */ + {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x9 */ + {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xa */ + {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xb */ + {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xc */ + {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xd */ + {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xe */ + {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0xf */ + {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e, 0x00, 0x00, 0x00, 0x00}, /* 0x10 */ + {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x11 */ + {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x12 (6f was 03) */ + {0x0087,0x15,0x06,0x00,0x06,0x37,1024, 768, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x13 */ + {0xc877,0x16,0x0b,0x06,0x06,0x37,1024, 768, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x14 */ + {0xc067,0x17,0x0f,0x49,0x06,0x37,1024, 768, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x15 */ + {0x0067,0x18,0x11,0x00,0x06,0x37,1024, 768, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x16 */ + {0x0047,0x19,0x16,0x8c,0x06,0x37,1024, 768, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x17 */ + {0x0107,0x1a,0x1b,0x00,0x06,0x37,1024, 768, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x18 */ + {0x0107,0x1b,0x1f,0x00,0x06,0x37,1024, 768, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x19 */ + {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1a */ + {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1b */ + {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1c */ + {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1d */ + {0x0227,0x20,0x21,0x09,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1e */ + {0x0407,0x21,0x22,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x1f */ + {0x0407,0x22,0x23,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x20 */ + {0x0407,0x23,0x25,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x21 */ + {0x0007,0x24,0x26,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x22 */ + {0x0007,0x25,0x2c,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x23 */ + {0x0007,0x26,0x34,0x00,0x09,0x3c,1600,1200, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x24 */ + {0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0x30, 0x56, 0x4e, 0x00, 0x00, 0x00, 0x00}, /* 0x25 */ + {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x26 */ + {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x27 */ + {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x28 */ + {0x8007,0x27,0x27,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x29 */ + {0x4007,0x28,0x29,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2a */ + {0x4007,0x29,0x2e,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2b */ + {0x4007,0x2a,0x30,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2c */ + {0x4007,0x2b,0x35,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2d */ + {0x4005,0x2c,0x39,0x00,0x00,0x68,1920,1440, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2e */ + {0x4007,0x2d,0x2b,0x00,0x00,0x6c,2048,1536, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x2f */ + {0x4007,0x2e,0x31,0x00,0x00,0x6c,2048,1536, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x30 */ + {0x4007,0x2f,0x33,0x00,0x00,0x6c,2048,1536, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x31 */ + {0x4007,0x30,0x37,0x00,0x00,0x6c,2048,1536, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x32 */ + {0x4005,0x31,0x38,0x00,0x00,0x6c,2048,1536, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x33 */ + {0x2077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00, 0x32, 0x40, 0x5e, 0x73}, /* 0x34 */ + {0x2047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00, 0x33, 0x07, 0xff, 0xff}, /* 0x35 */ + {0x2047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00, 0x34, 0x0a, 0xff, 0xff}, /* 0x36 */ + {0x2077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00, 0x35, 0x0b, 0x5f, 0x74}, /* 0x37 */ + {0x2047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00, 0x36, 0x11, 0xff, 0xff}, /* 0x38 */ + {0x2047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00, 0x37, 0x16, 0xff, 0xff}, /* 0x39 */ + {0x3137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00, 0x38, 0x19, 0x60, 0x75}, /* 0x3a */ + {0x3107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00, 0x39, 0x1e, 0xff, 0xff}, /* 0x3b */ + {0x3307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00, 0x3a, 0x20, 0xff, 0xff}, /* 0x3c */ + {0x0127,0x3b,0x19,0x08,0x0a,0x7c,1280, 960, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x3d */ + {0x0227,0x4c,0x59,0x08,0x0a,0x7c,1280, 960, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x3e */ + {0xc07f,0x4e,0x00,0x06,0x04,0x5a, 320, 240, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x3f */ /* FSTN 320x240 */ + {0x2077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00, 0x58, 0x19, 0x42, 0x5b}, /* 0x40 */ /* 0x5b was 0x12 */ + {0x2077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00, 0x59, 0x1e, 0xff, 0xff}, /* 0x41 */ + {0x2077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00, 0x5a, 0x20, 0xff, 0xff}, /* 0x42 */ + {0x0127,0x43,0x4d,0x08,0x0b,0x26,1400,1050, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x43 */ + {0x0207,0x4b,0x5a,0x08,0x0b,0x26,1400,1050, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x44 1400x1050-75Hz */ + {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x45 1152x864-60Hz */ + {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x46 1152x864-75Hz */ + {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x47 1152x864-85Hz */ + {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x48 848x480-38Hzi */ + {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x49 848x480-60Hz */ + {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x4a 856x480-38Hzi */ + {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x4b 856x480-60Hz */ + {0x0067,0x49,0x58,0x0c,0x1b,0x48,1360, 768, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x4c 1360x768-60Hz */ + {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x4d 768x576-56Hz */ + {0x2067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30, 0x00, 0x00, 0x5b, 0x19, 0x4f, 0x5c}, /* 0x4e 1280x800-60Hz */ + {0x2067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30, 0x00, 0x00, 0x5c, 0x1e, 0xff, 0xff}, /* 0x4f 1280x800-75Hz */ + {0x2067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30, 0x00, 0x00, 0x5d, 0x20, 0xff, 0xff}, /* 0x50 1280x800-85Hz */ + {0x0067,0x50,0x5d,0x0c,0x0e,0x17,1680,1050, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x51 1680x1050-60Hz */ + {0x0087,0x51,0x69,0x00,0x00,0x2c,1920,1080, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x52 1920x1080 60Hzi */ + {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x53 960x540 60Hz */ + {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0x54 960x600 60Hz */ + {0x2067,0x61,0x76,0x0d,0x22,0x1a,1280, 854, 0x30, 0x00, 0x00, 0x62, 0x19, 0x61, 0x76}, /* 0x55 1280x854-60Hz */ + {0x2067,0x61,0x76,0x0d,0x22,0x1a,1280, 854, 0x30, 0x00, 0x00, 0x63, 0x1e, 0xff, 0xff}, /* 0x56 1280x854-75Hz */ + {0x2067,0x61,0x76,0x0d,0x22,0x1a,1280, 854, 0x30, 0x00, 0x00, 0x64, 0x20, 0xff, 0xff}, /* 0x57 1280x854-85Hz */ + {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +static const struct SiS_CRT1Table SiS310_CRT1Table[] = { {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, /* 0x0 */ + 0x00}}, /* 0x0 */ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, /* 0x1 */ + 0x00}}, /* 0x1 */ {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0, 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05, - 0x01}}, /* 0x2 */ + 0x01}}, /* 0x2 */ {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, - 0x01}}, /* 0x3 */ + 0x01}}, /* 0x3 */ {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f, 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, /* 0x4 */ -#if 0 - {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, /* 0x5 */ -#endif - {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, /* 0x05 - corrected 640x480-60 */ + 0x00}}, /* 0x4 */ + {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, /* corrected 640x480-60 */ 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, - 0x00}}, -#if 0 - {{0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e, - 0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01, - 0x00}}, /* 0x6 */ -#endif - {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, /* 0x06 - corrected 640x480-72 */ + 0x00}}, /* 0x5 */ + {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e, /* corrected 640x480-72 */ 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01, - 0x00}}, + 0x00}}, /* 0x6 */ {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f, 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01, - 0x00}}, /* 0x7 */ + 0x00}}, /* 0x7 */ {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f, 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, - 0x00}}, /* 0x8 */ + 0x00}}, /* 0x8 */ {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f, 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, /* Corrected VBE */ - 0x61}}, /* 0x9 */ + 0x61}}, /* 0x9 */ {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e, 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05, - 0x61}}, /* 0xa */ + 0x61}}, /* 0xa */ {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e, 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, /* Corrected VBE */ - 0x61}}, /* 0xb */ + 0x61}}, /* 0xb */ {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, /* Corrected VDE, VBE */ - 0x00}}, /* 0xc */ + 0x00}}, /* 0xc */ {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, - 0x01}}, /* 0xd */ + 0x01}}, /* 0xd */ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0, 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06, - 0x01}}, /* 0xe */ + 0x01}}, /* 0xe */ {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0, 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06, - 0x01}}, /* 0xf */ + 0x01}}, /* 0xf */ {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0, 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06, - 0x01}}, /* 0x10 */ + 0x01}}, /* 0x10 */ {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0, 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06, - 0x01}}, /* 0x11 */ + 0x01}}, /* 0x11 */ {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0, 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06, - 0x61}}, /* 0x12 */ + 0x61}}, /* 0x12 */ {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0, 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06, - 0x61}}, /* 0x13 */ + 0x61}}, /* 0x13 */ {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0, 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06, - 0x61}}, /* 0x14 */ + 0x61}}, /* 0x14 */ {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f, 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02, - 0x00}}, /* 0x15 */ + 0x00}}, /* 0x15 */ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x16 */ + 0x01}}, /* 0x16 */ {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5, 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}}, /* 0x17 */ + 0x01}}, /* 0x17 */ {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5, 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02, - 0x01}}, /* 0x18 */ + 0x01}}, /* 0x18 */ {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5, 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02, - 0x01}}, /* 0x19 */ + 0x01}}, /* 0x19 */ {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5, 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02, - 0x62}}, /* 0x1a */ + 0x62}}, /* 0x1a */ {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5, 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02, - 0x62}}, /* 0x1b */ + 0x62}}, /* 0x1b */ {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba, 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03, - 0x00}}, /* 0x1c */ + 0x00}}, /* 0x1c */ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a, 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1d */ + 0x01}}, /* 0x1d */ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a, 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07, - 0x01}}, /* 0x1e */ + 0x01}}, /* 0x1e */ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a, 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07, - 0x01}}, /* 0x1f */ + 0x01}}, /* 0x1f */ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x20 */ + 0x00}}, /* 0x20 */ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x21 @ 4084 */ + 0x00}}, /* 0x21 */ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x22 */ + 0x00}}, /* 0x22 */ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x23 */ + 0x00}}, /* 0x23 */ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x24 */ + 0x00}}, /* 0x24 */ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x25 */ + 0x00}}, /* 0x25 */ {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10, 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04, - 0x00}}, /* 0x26 */ + 0x00}}, /* 0x26 */ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x27 */ + 0x00}}, /* 0x27 */ {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f, 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05, - 0x63}}, /* 0x28 */ + 0x63}}, /* 0x28 */ {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f, 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05, - 0x63}}, /* 0x29 */ + 0x63}}, /* 0x29 */ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2a */ + 0x00}}, /* 0x2a */ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2b */ + 0x00}}, /* 0x2b */ {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f, 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01, - 0x00}}, /* 0x2c */ + 0x00}}, /* 0x2c */ {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba, 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05, - 0x44}}, /* 0x2d */ + 0x44}}, /* 0x2d */ {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba, 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05, - 0x44}}, /* 0x2e */ + 0x44}}, /* 0x2e */ {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba, 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05, - 0x44}}, /* 0x2f */ + 0x44}}, /* 0x2f */ {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba, 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05, - 0x44}}, /* 0x30 */ + 0x44}}, /* 0x30 */ {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba, 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05, - 0x00}}, /* 0x31 */ + 0x00}}, /* 0x31 */ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba, 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06, - 0x01}}, /* 0x32 */ + 0x01}}, /* 0x32 */ {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba, 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06, - 0x01}}, /* 0x33 */ + 0x01}}, /* 0x33 */ {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba, 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06, - 0x01}}, /* 0x34 */ + 0x01}}, /* 0x34 */ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1, 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02, - 0x01}}, /* 0x35 */ + 0x01}}, /* 0x35 */ {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, - 0x01}}, /* 0x36 */ + 0x01}}, /* 0x36 */ {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, /* 95 was 15 - illegal HBE! */ 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, - 0x01}}, /* 0x37 */ + 0x01}}, /* 0x37 */ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x38 */ + 0x01}}, /* 0x38 */ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4, 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07, - 0x01}}, /* 0x39 */ + 0x01}}, /* 0x39 */ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4, 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07, - 0x01}}, /* 0x3a */ -#if 0 - {{0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef, /* 1280x960 - invalid */ - 0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07, - 0x01}}, /* 0x3b */ -#endif + 0x01}}, /* 0x3a */ {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff, /* 1280x960-60 - corrected */ 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07, - 0x01}}, /* 0x3b */ + 0x01}}, /* 0x3b */ {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e, 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, /* 0x3c */ - {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0, - 0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05, - 0x01}}, /* 0x3d */ + 0x00}}, /* 0x3c */ + {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0, /* 720x576, corrected to 60Hz */ + 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, + 0x41}}, /* 0x3d */ {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15, 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02, - 0x00}}, /* 0x3e */ + 0x00}}, /* 0x3e */ {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e, 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02, - 0x00}}, /* 0x3f */ + 0x00}}, /* 0x3f */ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, 0x01}}, /* 0x40 */ @@ -578,11 +483,11 @@ static const SiS_CRT1TableStruct SiS310_CRT1Table[]= {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* 1280x960-85 */ 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, 0x01}}, /* 0x4c */ - {{0x7b,0x5f,0x63,0x9f,0x6a,0x93,0x6f,0xf0, /* 768x576 */ - 0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05, - 0x01}}, /* 0x4d */ - {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, /* FSTN 320x480, TEMP - possibly invalid */ - 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, + {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0, /* 768x576, corrected to 60Hz */ + 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05, + 0x41}}, /* 0x4d */ + {{0x5f,0x27,0x4f,0x83,0x55,0x81,0x0b,0x3e, /* FSTN 320x240 (working) */ + 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, 0x00}}, /* 0x4e */ {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, /* 1280x800-60 */ 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07, @@ -601,10 +506,58 @@ static const SiS_CRT1TableStruct SiS310_CRT1Table[]= 0x01}}, /* 0x53 */ {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff, /* 1152x864-60 */ 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07, - 0x41}} /* 0x54 */ -}; - -static const SiS_MCLKDataStruct SiS310_MCLKData_0_315[] = + 0x41}}, /* 0x54 */ + {{0x5c,0x4f,0x4f,0x80,0x57,0x80,0xa3,0x1f, /* fake 640x400@60Hz (for LCD and TV, not actually used) */ + 0x98,0x8c,0x8f,0x96,0xa4,0x30,0x00,0x05, + 0x40}}, /* 0x55 */ + {{0x2c,0x27,0x27,0x90,0x2d,0x92,0xa4,0x1f, /* fake 320x200@60Hz (for LCD and TV, not actually used) */ + 0x98,0x8c,0x8f,0x96,0xa5,0x30,0x00,0x04, + 0x00}}, /* 0x56 */ + {{0xd7,0xc7,0xc7,0x9b,0xd1,0x15,0xd1,0x10, /* 1600x1200 for LCDA */ + 0xb2,0x86,0xaf,0xb0,0xd2,0x2f,0x00,0x03, + 0x00}}, /* 0x57 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xdc, /* 1280x768 (1280x1024) 60 Hz */ + 0x92,0x86,0xff,0x91,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x58 */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xdc, /* 1280x768 (1280x1024) 75 Hz */ + 0x92,0x86,0xff,0x91,0x29,0x21,0x00,0x07, + 0x01}}, /* 0x59 */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xdc, /* 1280x768 (1280x1024) 85 Hz */ + 0x95,0x89,0xff,0x94,0x2f,0x21,0x00,0x07, + 0x01}}, /* 0x5a */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xde, /* 1280x800 (1280x1024) 60 Hz */ + 0xa2,0x86,0x1f,0xa1,0x29,0x01,0x00,0x07, + 0x01}}, /* 0x5b */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xde, /* 1280x800 (1280x1024) 75 Hz */ + 0xa2,0x86,0x1f,0xa1,0x29,0x01,0x00,0x07, + 0x01}}, /* 0x5c */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xde, /* 1280x800 (1280x1024) 85 Hz */ + 0xa5,0x89,0x1f,0xa4,0x2f,0x01,0x00,0x07, + 0x01}}, /* 0x5d */ + {{0x7f,0x63,0x63,0x83,0x6d,0x1d,0x0b,0x3e, /* 800x480 (wide) 60 Hz */ + 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x06, + 0x00}}, /* 0x5e */ + {{0xa0,0x7f,0x7f,0x84,0x85,0x97,0x52,0xf0, /* 1024x576 (wide) 60 Hz */ + 0x41,0x85,0x3f,0x40,0x53,0x00,0x00,0x02, + 0x01}}, /* 0x5f */ + {{0xc9,0x9f,0x9f,0x8d,0xb0,0x15,0xec,0xf0, /* 1280x720 (wide) 60 Hz */ + 0xd4,0x89,0xcf,0xd3,0xed,0x20,0x00,0x07, + 0x01}}, /* 0x60 */ + {{0xcb,0x9f,0x9f,0x8f,0xa5,0x13,0x5b,0xff, /* 1280x854-60 wide */ + 0x56,0x89,0x55,0x55,0x5c,0x30,0x00,0x07, + 0x01}}, /* 0x61 */ + {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xde, /* 1280x854 (1280x1024) 60 Hz */ + 0xbd,0x81,0x55,0xbc,0x29,0x01,0x00,0x07, + 0x41}}, /* 0x62 */ + {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xde, /* 1280x854 (1280x1024) 75 Hz */ + 0xbd,0x81,0x55,0xbc,0x29,0x01,0x00,0x07, + 0x41}}, /* 0x63 */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xde, /* 1280x854 (1280x1024) 85 Hz */ + 0xc0,0x84,0x55,0xbf,0x2f,0x01,0x00,0x07, + 0x41}} /* 0x64 */ +}; + +static const struct SiS_MCLKData SiS310_MCLKData_0_315[] = { { 0x3b,0x22,0x01,143}, { 0x5c,0x23,0x01,166}, @@ -616,7 +569,7 @@ static const SiS_MCLKDataStruct SiS310_MCLKData_0_315[] = { 0x5c,0x23,0x01,166} }; -static const SiS_MCLKDataStruct SiS310_MCLKData_0_650[] = +static const struct SiS_MCLKData SiS310_MCLKData_0_650[] = { { 0x5a,0x64,0x82, 66}, { 0xb3,0x45,0x82, 83}, @@ -628,7 +581,7 @@ static const SiS_MCLKDataStruct SiS310_MCLKData_0_650[] = { 0x37,0x22,0x82,133} }; -static const SiS_MCLKDataStruct SiS310_MCLKData_0_330[] = +static const struct SiS_MCLKData SiS310_MCLKData_0_330[] = { { 0x5c,0x23,0x01,166}, { 0x5c,0x23,0x01,166}, @@ -640,7 +593,7 @@ static const SiS_MCLKDataStruct SiS310_MCLKData_0_330[] = { 0x79,0x06,0x01,250} }; -static const SiS_MCLKDataStruct SiS310_MCLKData_0_660[] = +static const struct SiS_MCLKData SiS310_MCLKData_0_660[] = { { 0x5c,0x23,0x82,166}, { 0x5c,0x23,0x82,166}, @@ -652,7 +605,7 @@ static const SiS_MCLKDataStruct SiS310_MCLKData_0_660[] = { 0x37,0x21,0x82,200} }; -static const SiS_MCLKDataStruct SiS310_MCLKData_0_760[] = +static const struct SiS_MCLKData SiS310_MCLKData_0_760[] = { { 0x37,0x22,0x82,133}, { 0x5c,0x23,0x82,166}, @@ -664,7 +617,7 @@ static const SiS_MCLKDataStruct SiS310_MCLKData_0_760[] = { 0x37,0x21,0x82,200} }; -static const SiS_MCLKDataStruct SiS310_MCLKData_0_761[] = +static const struct SiS_MCLKData SiS310_MCLKData_0_761[] = { { 0x37,0x22,0x82,133}, /* Preliminary */ { 0x5c,0x23,0x82,166}, @@ -676,7 +629,7 @@ static const SiS_MCLKDataStruct SiS310_MCLKData_0_761[] = { 0x37,0x21,0x82,200} }; -static const SiS_MCLKDataStruct SiS310_MCLKData_0_340[] = +static const struct SiS_MCLKData SiS310_MCLKData_0_340[] = { { 0x79,0x06,0x01,250}, { 0x7c,0x08,0x01,200}, @@ -688,9 +641,9 @@ static const SiS_MCLKDataStruct SiS310_MCLKData_0_340[] = { 0x29,0x01,0x81,300} }; -static const SiS_MCLKDataStruct SiS310_MCLKData_1[] = /* ECLK */ +static const struct SiS_MCLKData SiS310_MCLKData_1[] = /* ECLK */ { - { 0x29,0x21,0x82,150}, + { 0x29,0x21,0x82,150}, { 0x5c,0x23,0x82,166}, { 0x65,0x23,0x82,183}, { 0x37,0x21,0x82,200}, @@ -700,7 +653,7 @@ static const SiS_MCLKDataStruct SiS310_MCLKData_1[] = /* ECLK */ { 0x37,0x22,0x82,133} }; -static const SiS_MCLKDataStruct SiS310_MCLKData_1_340[] = +static const struct SiS_MCLKData SiS310_MCLKData_1_340[] = { { 0x7c,0x08,0x01,200}, { 0x7c,0x08,0x01,200}, @@ -712,7 +665,7 @@ static const SiS_MCLKDataStruct SiS310_MCLKData_1_340[] = { 0x29,0x01,0x81,300} }; -static SiS_VCLKDataStruct SiS310_VCLKData[]= +static struct SiS_VCLKData SiS310_VCLKData[] = { { 0x1b,0xe1, 25}, /* 0x00 */ { 0x4e,0xe4, 28}, /* 0x01 */ @@ -805,7 +758,7 @@ static SiS_VCLKDataStruct SiS310_VCLKData[]= { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ { 0x52,0x07,149}, /* 0x59 1280x960-85 */ { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ - { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ + { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ { 0x45,0x25, 83}, /* 0x5c 1280x800 */ { 0x70,0x0a,147}, /* 0x5d 1680x1050 */ { 0x70,0x24,162}, /* 0x5e 1600x1200 */ @@ -823,10 +776,19 @@ static SiS_VCLKDataStruct SiS310_VCLKData[]= { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ { 0x45,0x25, 83}, /* 0x6c 1280x800 */ - { 0x70,0x28, 90} /* 0x6d 1152x864@60 */ + { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */ + { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */ + { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + { 0x2b,0xc2, 35}, /* 0x71 768x576@60 */ + { 0xa8,0x42,131}, /* 0x72 1600x1200@60 for LCDA */ + { 0x1b,0xc1, 34}, /* 0x73 800x480 60Hz (wide) */ + { 0x41,0x64, 48}, /* 0x74 1024x576 60Hz (wide) */ + { 0x52,0x27, 75}, /* 0x75 1280x720 60Hz (wide) */ + { 0x75,0x13, 84} /* 0x76 1280x854 60Hz (wide) */ }; -static SiS_VBVCLKDataStruct SiS310_VBVCLKData[]= +static struct SiS_VBVCLKData SiS310_VBVCLKData[] = { { 0x1b,0xe1, 25}, /* 0x00 */ { 0x4e,0xe4, 28}, /* 0x01 */ @@ -858,12 +820,6 @@ static SiS_VBVCLKDataStruct SiS310_VBVCLKData[]= { 0x5e,0x43,113}, /* 0x1b */ { 0xbc,0x44,116}, /* 0x1c */ { 0xe0,0x46,132}, /* 0x1d */ -#if 0 - { 0xd4,0x28,135}, /* 0x1e */ - { 0xea,0x2a,139}, /* 0x1f */ - { 0x41,0x22,157}, /* 0x20 */ - { 0x70,0x24,162}, /* 0x21 */ -#endif { 0xe2,0x46,135}, /* 0x1e */ /* 1280x1024-75, better clock for VGA2 */ { 0xe5,0x46,139}, /* 0x1f */ /* 1024x768-120, better clock for VGA2 */ { 0x15,0x01,157}, /* 0x20 */ /* 1280x1024-85, better clock for VGA2 */ @@ -912,7 +868,7 @@ static SiS_VBVCLKDataStruct SiS310_VBVCLKData[]= { 0x34,0x61, 95}, /* 0x4b UNUSED */ { 0x78,0x27,108}, /* 0x4c UNUSED */ { 0x66,0x43,123}, /* 0x4d 1400x1050-60 */ - { 0x41,0x4e, 21}, /* 0x4e UNUSED */ + { 0x41,0x4e, 21}, /* 0x4e */ { 0xa1,0x4a, 29}, /* 0x4f UNUSED */ { 0x19,0x42, 42}, /* 0x50 UNUSED */ { 0x54,0x46, 58}, /* 0x51 UNUSED */ @@ -925,7 +881,7 @@ static SiS_VBVCLKDataStruct SiS310_VBVCLKData[]= { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) TEMP, UNUSED */ { 0x52,0x07,149}, /* 0x59 1280x960-85 */ { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ - { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD (TMDS) */ + { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD (TMDS) */ { 0xce,0x1e, 73}, /* 0x5c 1280x800_2 LCD (SiS LVDS) - (CRT1: 45 25 83) */ { 0xbe,0x44,121}, /* 0x5d 1680x1050 LCD */ { 0x70,0x24,162}, /* 0x5e 1600x1200 LCD */ @@ -943,57 +899,33 @@ static SiS_VBVCLKDataStruct SiS310_VBVCLKData[]= { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */ { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */ { 0x9c,0x62, 69}, /* 0x6c 1280x800 (SiS TMDS) (special) */ - { 0x70,0x28, 90} /* 0x6d 1152x864@60 */ + { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */ + { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */ + { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + { 0x2b,0xc2, 35}, /* 0x71 768@576@60 */ + { 0xa8,0x42,131}, /* 0x72 1600x1200@60 for LCDA */ + { 0x1b,0xc1, 34}, /* 0x73 800x480 60Hz (wide) */ + { 0x41,0x64, 48}, /* 0x74 1024x576 60Hz (wide) */ + { 0x52,0x27, 75}, /* 0x75 1280x720 60Hz (wide) */ + { 0x75,0x13, 84} /* 0x76 1280x854 60Hz (SiS LVDS) LCD */ }; -static const DRAM4Type SiS310_SR15[8] = { - {0x00,0x04,0x60,0x60}, - {0x0f,0x0f,0x0f,0x0f}, - {0xba,0xba,0xba,0xba}, - {0xa9,0xa9,0xac,0xac}, - {0xa0,0xa0,0xa0,0xa8}, - {0x00,0x00,0x02,0x02}, - {0x30,0x30,0x40,0x40}, - {0x00,0xa5,0xfb,0xf6} -}; - -#ifdef LINUX_KERNEL - -static UCHAR SiS310_SR07 = 0x18; - -static const DRAM4Type SiS310_CR40[5] = { - {0x77,0x77,0x33,0x33}, - {0x77,0x77,0x33,0x33}, - {0x00,0x00,0x00,0x00}, - {0x5b,0x5b,0x03,0x03}, - {0x00,0x00,0xf0,0xf8} +static const unsigned char SiS310_SR15[4 * 8] = +{ + 0x00,0x04,0x60,0x60, + 0x0f,0x0f,0x0f,0x0f, + 0xba,0xba,0xba,0xba, + 0xa9,0xa9,0xac,0xac, + 0xa0,0xa0,0xa0,0xa8, + 0x00,0x00,0x02,0x02, + 0x30,0x30,0x40,0x40, + 0x00,0xa5,0xfb,0xf6 }; -static UCHAR SiS310_CR49[] = {0xaa,0x88}; -static UCHAR SiS310_SR1F = 0x00; -static UCHAR SiS310_SR21 = 0xa5; -static UCHAR SiS310_SR22 = 0xfb; -static UCHAR SiS310_SR23 = 0xf6; -static UCHAR SiS310_SR24 = 0x0d; -static UCHAR SiS310_SR25[] = {0x33,0x3}; -static UCHAR SiS310_SR31 = 0x00; -static UCHAR SiS310_SR32 = 0x11; -static UCHAR SiS310_SR33 = 0x00; -static UCHAR SiS310_CRT2Data_1_2 = 0x00; -static UCHAR SiS310_CRT2Data_4_D = 0x00; -static UCHAR SiS310_CRT2Data_4_E = 0x00; -static UCHAR SiS310_CRT2Data_4_10 = 0x80; -static const USHORT SiS310_RGBSenseData = 0xd1; -static const USHORT SiS310_VideoSenseData = 0xb9; -static const USHORT SiS310_YCSenseData = 0xb3; -static const USHORT SiS310_RGBSenseData2 = 0x0190; -static const USHORT SiS310_VideoSenseData2 = 0x0174; -static const USHORT SiS310_YCSenseData2 = 0x016b; -#endif - -static const SiS_PanelDelayTblStruct SiS310_PanelDelayTbl[]= +static const struct SiS_PanelDelayTbl SiS310_PanelDelayTbl[] = { - {{0x10,0x40}}, + {{0x10,0x40}}, {{0x10,0x40}}, {{0x10,0x40}}, {{0x10,0x40}}, @@ -1011,7 +943,7 @@ static const SiS_PanelDelayTblStruct SiS310_PanelDelayTbl[]= {{0x10,0x40}} }; -static const SiS_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]= +static const struct SiS_PanelDelayTbl SiS310_PanelDelayTblLVDS[] = { {{0x28,0xc8}}, {{0x28,0xc8}}, @@ -1035,18 +967,18 @@ static const SiS_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]= /* SIS VIDEO BRIDGE ----------------------------------------- */ /**************************************************************/ -static const SiS_LCDDataStruct SiS310_St2LCD1024x768Data[] = +static const struct SiS_LCDData SiS310_St2LCD1024x768Data[] = { { 62, 25, 800, 546,1344, 806}, { 32, 15, 930, 546,1344, 806}, - { 62, 25, 800, 546,1344, 806}, + { 62, 25, 800, 546,1344, 806}, { 104, 45, 945, 496,1344, 806}, { 62, 25, 800, 546,1344, 806}, { 31, 18,1008, 624,1344, 806}, { 1, 1,1344, 806,1344, 806} }; -static const SiS_LCDDataStruct SiS310_ExtLCD1024x768Data[] = +static const struct SiS_LCDData SiS310_ExtLCD1024x768Data[] = { { 42, 25,1536, 419,1344, 806}, { 48, 25,1536, 369,1344, 806}, @@ -1057,7 +989,7 @@ static const SiS_LCDDataStruct SiS310_ExtLCD1024x768Data[] = { 1, 1,1344, 806,1344, 806} }; -static const SiS_LCDDataStruct SiS310_St2LCD1280x1024Data[] = +static const struct SiS_LCDData SiS310_St2LCD1280x1024Data[] = { { 22, 5, 800, 510,1650,1088}, { 22, 5, 800, 510,1650,1088}, @@ -1069,7 +1001,7 @@ static const SiS_LCDDataStruct SiS310_St2LCD1280x1024Data[] = { 1, 1,1688,1066,1688,1066} }; -static const SiS_LCDDataStruct SiS310_ExtLCD1280x1024Data[] = +static const struct SiS_LCDData SiS310_ExtLCD1280x1024Data[] = { { 211, 60,1024, 501,1688,1066}, { 211, 60,1024, 508,1688,1066}, @@ -1081,45 +1013,22 @@ static const SiS_LCDDataStruct SiS310_ExtLCD1280x1024Data[] = { 1, 1,1688,1066,1688,1066} }; -static const SiS_Part2PortTblStruct SiS310_CRT2Part2_1024x768_1[] = +static const struct SiS_Part2PortTbl SiS310_CRT2Part2_1024x768_1[] = { - {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x38,0x13,0x16,0x0c,0xe6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} + {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x38,0x13,0x16,0x0c,0xe6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} }; -/* *** LCDA *** */ - -#if 0 -static const SiS_LVDSDataStruct SiS_LCDA1600x1200Data_1[]= -{ /* Clevo, 651+301C */ - {1200, 450, 2048,1250}, - {1200, 400, 2048,1250}, - {1280, 450, 2048,1250}, - {1280, 400, 2048,1250}, - {1200, 530, 2048,1250}, - {1360, 650, 2048,1250}, - {1584, 818, 2048,1250}, - {1688,1066, 2048,1250}, - {1688,1066, 2048,1250}, -#if 0 - {2048,1250, 2048,1250} /* this should be correct */ -#endif -#if 1 - {2160,1250, 2048,1250} /* ? */ -#endif -}; -#endif - /**************************************************************/ /* LVDS, CHRONTEL ------------------------------------------- */ /**************************************************************/ -static const SiS_LVDSDataStruct SiS310_CHTVUPALData[]= +static const struct SiS_LVDSData SiS310_CHTVUPALData[] = { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1130,7 +1039,7 @@ static const SiS_LVDSDataStruct SiS310_CHTVUPALData[]= {1400,1000,1400,1000} }; -static const SiS_LVDSDataStruct SiS310_CHTVOPALData[]= +static const struct SiS_LVDSData SiS310_CHTVOPALData[] = { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1138,10 +1047,10 @@ static const SiS_LVDSDataStruct SiS310_CHTVOPALData[]= {1008, 625,1008, 625}, { 840, 625, 840, 625}, { 944, 625, 944, 625}, - {1400, 875,1400, 875} + {1400, 875,1400, 875} }; -static const SiS_LVDSDataStruct SiS310_CHTVUPALMData[]= +static const struct SiS_LVDSData SiS310_CHTVUPALMData[] = { { 840, 600, 840, 600}, { 840, 600, 840, 600}, @@ -1149,10 +1058,10 @@ static const SiS_LVDSDataStruct SiS310_CHTVUPALMData[]= { 840, 600, 840, 600}, { 784, 600, 784, 600}, {1064, 750,1064, 750}, - {1160, 945,1160, 945} + {1160, 945,1160, 945} }; -static const SiS_LVDSDataStruct SiS310_CHTVOPALMData[]= +static const struct SiS_LVDSData SiS310_CHTVOPALMData[] = { { 840, 525, 840, 525}, { 840, 525, 840, 525}, @@ -1160,10 +1069,10 @@ static const SiS_LVDSDataStruct SiS310_CHTVOPALMData[]= { 840, 525, 840, 525}, { 784, 525, 784, 525}, {1040, 700,1040, 700}, - {1160, 840,1160, 840} + {1160, 840,1160, 840} }; -static const SiS_LVDSDataStruct SiS310_CHTVUPALNData[]= +static const struct SiS_LVDSData SiS310_CHTVUPALNData[] = { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1174,7 +1083,7 @@ static const SiS_LVDSDataStruct SiS310_CHTVUPALNData[]= {1400,1000,1400,1000} }; -static const SiS_LVDSDataStruct SiS310_CHTVOPALNData[]= +static const struct SiS_LVDSData SiS310_CHTVOPALNData[] = { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1182,10 +1091,10 @@ static const SiS_LVDSDataStruct SiS310_CHTVOPALNData[]= {1008, 625,1008, 625}, { 840, 625, 840, 625}, { 944, 625, 944, 625}, - {1400, 875,1400, 875} + {1400, 875,1400, 875} }; -static const SiS_LVDSDataStruct SiS310_CHTVSOPALData[]= /* (super overscan - no effect on 7019) */ +static const struct SiS_LVDSData SiS310_CHTVSOPALData[] = /* (super overscan - no effect on 7019) */ { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1196,1333 +1105,10 @@ static const SiS_LVDSDataStruct SiS310_CHTVSOPALData[]= /* (super overscan - {1400, 875,1400, 875} }; - -static const SiS_LVDSDesStruct SiS310_PanelType00_1[]= /* 800x600 */ -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType01_1[]= /* 1024x768 */ -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 805}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType02_1[]= /* 1280x1024 */ -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 1065}, - { 0, 0}, - { 0, 0} -}; - - -static const SiS_LVDSDesStruct SiS310_PanelType03_1[]= -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType04_1[]= -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType05_1[]= -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType06_1[]= -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType07_1[]= -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType08_1[]= /* 1400x1050 */ -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType09_1[]= /* 1280x768 */ -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0a_1[]= /* 1600x1200 */ -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0b_1[]= /* 640x480_2 */ -{ - { 0, 524}, - { 0, 524}, - { 0, 524}, - { 0, 524}, - { 0, 524}, - { 0, 524}, - { 8, 524}, - { 0, 524} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0c_1[]= /* 640x480_3 */ -{ - { 0, 524}, - { 0, 524}, - { 0, 524}, - { 0, 524}, - { 0, 524}, - { 0, 524}, - { 8, 524}, - { 0, 524} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0d_1[]= -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0e_1[]= -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0f_1[]= -{ - {1343, 798}, - {1343, 794}, - {1343, 798}, - {1343, 794}, - {1343, 0}, - {1343, 0}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType00_2[]= -{ - {980, 528}, - {980, 503}, - {980, 528}, - {980, 503}, - {980, 568}, - { 0, 628}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType01_2[]= -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 806}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType02_2[]= -{ - {1368, 754}, - {1368, 729}, - {1368, 754}, - {1368, 729}, - {1368, 794}, - {1448, 854}, - {1560, 938}, - { 0,1066}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType03_2[]= -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType04_2[]= -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType05_2[]= -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType06_2[]= -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType07_2[]= -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType08_2[]= /* 1400x1050 */ -{ - {1308, 741}, - {1308, 716}, - {1308, 741}, - {1308, 716}, - {1308, 781}, - {1388, 841}, - {1500, 925}, - {1628,1053}, - { 0,1065}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType09_2[]= /* 1280x768 */ -{ - {1083, 622}, - {1083, 597}, - {1083, 622}, - {1083, 597}, - {1083, 662}, - {1163, 722}, - {1286, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0a_2[]= /* 1600x1200 */ -{ - {1568, 920}, - {1568, 895}, - {1568, 920}, - {1568, 895}, - {1568, 960}, - {1648,1020}, - {1760,1104}, - {1888,1232}, - {1948,1245}, - { 0, 0} -#if 0 - {1568, 850}, - {1568, 825}, - {1568, 850}, - {1568, 825}, - {1568, 890}, - {1648, 950}, - {1760,1034}, - {1888,1162}, - {1948,1175}, - { 0, 0} -#endif -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0b_2[]= /* 640x480_2 */ -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0c_2[]= /* 640x480_3 */ -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0d_2[]= -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0e_2[]= -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelType0f_2[] = -{ - {1152, 622}, - {1152, 597}, - {1152, 622}, - {1152, 597}, - {1152, 662}, - {1232, 722}, - { 0, 805}, - { 0, 794}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelTypeNS_1[]= -{ - { 8, 0}, - { 8, 0}, - { 8, 0}, - { 8, 0}, - { 8, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 806}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS310_PanelTypeNS_2[] = -{ - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0} -}; - -/* CRT1 CRTC for SlaveModes and LCDA */ - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1[] = -{ - {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f, - 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, - 0x00 }}, - {{0x6b,0x4f,0x8f,0x55,0x85,0x78,0x1f, - 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, - 0x00 }}, - {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f, - 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, - 0x00 }}, - {{0x6b,0x4f,0x8f,0x55,0x85,0x78,0x1f, - 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, - 0x00 }}, - {{0x6b,0x4f,0x8f,0x55,0x85,0xfa,0x1f, - 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, - 0x00 }}, - {{0x7f,0x63,0x83,0x69,0x19,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1_H[] = -{ - {{0x43,0x27,0x87,0x2d,0x1d,0xaa,0x1f, - 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, - 0x00 }}, - {{0x43,0x27,0x87,0x2d,0x1d,0x78,0x1f, - 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, - 0x00 }}, - {{0x43,0x27,0x87,0x2d,0x1d,0xfa,0x1f, - 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, - 0x00 }}, - {{0x43,0x27,0x87,0x2d,0x1d,0x78,0x1f, - 0x5e,0x83,0x5d,0x79,0x10,0x00,0x05, - 0x00 }}, - {{0x43,0x27,0x87,0x2d,0x1d,0xfa,0x1f, - 0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05, - 0x00 }}, - {{0x4d,0x31,0x91,0x37,0x07,0x72,0xf0, - 0x58,0x8d,0x57,0x73,0x20,0x00,0x01, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2[]= -{ - {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, - 0xff,0x84,0x8f,0x73,0x00,0x00,0x06, - 0x00 }}, - {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, - 0xe6,0x8b,0x5d,0x73,0x00,0x00,0x06, - 0x00 }}, - {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, - 0xff,0x84,0x8f,0x73,0x00,0x00,0x06, - 0x00 }}, - {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, - 0xe6,0x8b,0x5d,0x73,0x00,0x00,0x06, - 0x00 }}, - {{0x7f,0x4f,0x83,0x62,0x12,0x72,0xba, - 0x27,0x8c,0xdf,0x73,0x00,0x00,0x06, - 0x00 }}, - {{0x7f,0x63,0x83,0x69,0x19,0x72,0xf0, - 0x58,0x8d,0x57,0x73,0x20,0x00,0x06, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2_H[] = -{ - {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e, - 0xff,0x84,0x8f,0x73,0x00,0x00,0x01, - 0x00 }}, - {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e, - 0xd6,0x8b,0x5d,0x73,0x00,0x00,0x01, - 0x00 }}, - {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e, - 0xff,0x84,0x8f,0x73,0x00,0x00,0x01, - 0x00 }}, - {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e, - 0xd6,0x8b,0x5d,0x73,0x00,0x00,0x01, - 0x00 }}, - {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0xba, - 0x27,0x8c,0xdf,0x73,0x00,0x00,0x01, - 0x00 }}, - {{0x4d,0x31,0x91,0x3a,0x0a,0x72,0xf0, - 0x63,0x88,0x57,0x73,0x00,0x00,0x01, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1[] = -{ - {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x97,0x53,0x84,0x82,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x97,0x53,0x84,0x82,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x97,0x53,0x84,0x04,0x3e, - 0xE2,0x89,0xDf,0x05,0x00,0x00,0x05, - 0x00}}, - {{0x87,0x63,0x8B,0x67,0x18,0x7c,0xf0, - 0x5A,0x81,0x57,0x7D,0x00,0x00,0x06, - 0x01}}, - {{0xA3,0x7f,0x87,0x83,0x94,0x24,0xf5, - 0x02,0x89,0xFf,0x25,0x10,0x00,0x02, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1_H[] = -{ - {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x05, - 0x00 }}, - {{0x4b,0x27,0x8f,0x2b,0x1c,0x82,0x1f, - 0x60,0x87,0x5D,0x83,0x01,0x00,0x05, - 0x00}}, - {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x05, - 0x00}}, - {{0x4b,0x27,0x8f,0x2b,0x1c,0x82,0x1f, - 0x60,0x87,0x5D,0x83,0x01,0x00,0x05, - 0x00}}, - {{0x4b,0x27,0x8f,0x2b,0x1c,0x04,0x3e, - 0xE2,0x89,0xDf,0x05,0x00,0x00,0x05, - 0x00}}, - {{0x55,0x31,0x99,0x35,0x06,0x7c,0xf0, - 0x5A,0x81,0x57,0x7D,0x00,0x00,0x01, - 0x01}}, - {{0x63,0x3F,0x87,0x43,0x94,0x24,0xf5, - 0x02,0x89,0xFf,0x25,0x10,0x00,0x01, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2[] = -{ - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x57,0x8e,0x8f,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x3e,0x85,0x5d,0x25,0x10,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x57,0x8e,0x8f,0x25,0x30,0x00,0x06, - 0x00 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x3e,0x85,0x5d,0x25,0x10,0x00,0x06, - 0x01 }}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x7f,0x86,0xdf,0x25,0x10,0x00,0x06, - 0x00 }}, - {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1, - 0xbb,0x82,0x57,0x25,0x10,0x00,0x02, - 0x01 }}, - {{0xa3,0x7f,0x87,0x83,0x94,0x24,0xf5, - 0x02,0x89,0xff,0x25,0x10,0x00,0x02, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2_H[] = -{ - {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, - 0x57,0x8e,0x8f,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, - 0x3e,0x85,0x5d,0x25,0x10,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, - 0x57,0x8e,0x8f,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, - 0x3e,0x85,0x5d,0x25,0x10,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, - 0x7f,0x86,0xdf,0x25,0x10,0x00,0x01, - 0x00 }}, - {{0x71,0x31,0x95,0x46,0x97,0x24,0xf1, - 0xbb,0x82,0x57,0x25,0x10,0x00,0x01, - 0x01 }}, - {{0x63,0x3f,0x87,0x46,0x97,0x24,0xf5, - 0x0f,0x86,0xff,0x25,0x30,0x00,0x01, - 0x01 }} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1[] = -{ - {{0x7e,0x4f,0x82,0x58,0x04,0xb8,0x1f, - 0x90,0x84,0x8f,0xb9,0x30,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x82,0x58,0x04,0x86,0x1f, - 0x5e,0x82,0x5d,0x87,0x10,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x82,0x58,0x04,0xb8,0x1f, - 0x90,0x84,0x8f,0xb9,0x30,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x82,0x58,0x04,0x86,0x1f, - 0x5e,0x82,0x5d,0x87,0x10,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x82,0x58,0x04,0x08,0x3e, - 0xe0,0x84,0xdf,0x09,0x00,0x00,0x06, - 0x00}}, - {{0x92,0x63,0x96,0x6c,0x18,0x80,0xf0, - 0x58,0x8c,0x57,0x81,0x20,0x00,0x06, - 0x01}}, - {{0xae,0x7f,0x92,0x88,0x94,0x28,0xf5, - 0x00,0x84,0xff,0x29,0x10,0x00,0x02, - 0x01}}, - {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, - 0x00,0x84,0xff,0x29,0x09,0x00,0x07, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1_H[] = -{ - {{0x56,0x27,0x9a,0x31,0x1c,0xb8,0x1f, - 0x90,0x84,0x8f,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x56,0x27,0x9a,0x31,0x1c,0x86,0x1f, - 0x5e,0x82,0x5d,0x87,0x10,0x00,0x05, - 0x00}}, - {{0x56,0x27,0x9a,0x31,0x1c,0xb8,0x1f, - 0x90,0x84,0x8f,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x56,0x27,0x9a,0x31,0x1c,0x86,0x1f, - 0x5e,0x82,0x5d,0x87,0x10,0x00,0x05, - 0x01}}, - {{0x56,0x27,0x9a,0x31,0x1c,0x08,0x3e, - 0xe0,0x84,0xdf,0x09,0x00,0x00,0x05, - 0x00}}, - {{0x60,0x31,0x84,0x3a,0x86,0x80,0xf0, - 0x58,0x8c,0x57,0x81,0x20,0x00,0x01, - 0x01}}, - {{0x6e,0x3f,0x92,0x48,0x94,0x28,0xf5, - 0x00,0x84,0xff,0x29,0x10,0x00,0x01, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2[] = -{ - {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, - 0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x02, - 0x01}}, - {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, - 0xaf,0x83,0x44,0x43,0x21,0x00,0x02, - 0x01}}, - {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, - 0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x02, - 0x01}}, - {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, - 0xaf,0x83,0x44,0x43,0x21,0x00,0x02, - 0x01}}, - {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, - 0xf0,0x84,0x85,0x84,0x11,0x00,0x02, - 0x01}}, - {{0xce,0x63,0x92,0x8b,0x19,0x28,0xd4, - 0x3f,0x83,0x57,0x29,0x01,0x00,0x03, - 0x01}}, - {{0xce,0x7f,0x92,0x99,0x07,0x28,0xd4, - 0x93,0x87,0xff,0x29,0x21,0x00,0x07, - 0x01}}, - {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, - 0x00,0x84,0xff,0x29,0x09,0x00,0x07, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2_H[] = -{ - {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, - 0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x06, - 0x01}}, - {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, - 0xaf,0x83,0x44,0x43,0x21,0x00,0x06, - 0x01}}, - {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, - 0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x06, - 0x01}}, - {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, - 0xfa,0x83,0x44,0x43,0x31,0x00,0x06, - 0x01}}, - {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, - 0xf0,0x84,0x85,0x84,0x11,0x00,0x06, - 0x01}}, - {{0x9c,0x31,0x80,0x59,0x87,0x28,0xd4, - 0x3f,0x83,0x57,0x29,0x01,0x00,0x06, - 0x01}}, - {{0x8e,0x3f,0x92,0x59,0x07,0x28,0xd4, - 0x93,0x87,0xff,0x29,0x21,0x00,0x06, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_1[] = -{ - {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f, - 0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f, - 0x5e,0x81,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f, - 0x90,0x83,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f, - 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x93,0x54,0x82,0xee,0x1f, - 0xdf,0x82,0xdf,0xef,0x10,0x00,0x05, - 0x00}}, - {{0x83,0x63,0x87,0x68,0x16,0x66,0xf0, - 0x57,0x8e,0x57,0x67,0x20,0x00,0x06, - 0x01}}, - {{0x9f,0x7f,0x83,0x84,0x92,0x0e,0xf1, - 0xff,0x86,0xff,0x0f,0x10,0x00,0x02, - 0x01,}}, - {{0xbf,0x9f,0x83,0xa4,0x12,0x0e,0xde, - 0xff,0x86,0xff,0x0f,0x01,0x00,0x07, - 0x01}}, - {{0xce,0xae,0x92,0xb3,0x01,0x28,0x10, - 0x19,0x80,0x19,0x29,0x0f,0x00,0x03, - 0x00}} -#if 0 - {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f, - 0x93,0x86,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f, - 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f, - 0x93,0x86,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f, - 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x93,0x54,0x82,0xee,0x1f, - 0xe2,0x86,0xdf,0xef,0x10,0x00,0x05, - 0x00}}, - {{0x83,0x63,0x87,0x68,0x16,0x66,0xf0, - 0x5a,0x8e,0x57,0x67,0x20,0x00,0x06, - 0x01}}, - {{0x9f,0x7f,0x83,0x84,0x92,0x0e,0xf5, - 0x02,0x86,0xff,0x0f,0x10,0x00,0x02, - 0x01}}, - {{0xbf,0x9f,0x83,0xa4,0x12,0x0e,0x5a, - 0x02,0x86,0xff,0x0f,0x09,0x00,0x07, - 0x01}}, - {{0xce,0xae,0x92,0xb3,0x01,0x28,0x10, - 0x1a,0x80,0x19,0x29,0x0f,0x00,0x03, - 0x00}} -#endif -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_1_H[] = -{ - {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f, - 0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, - 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f, - 0x90,0x83,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, - 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f, - 0xdf,0x86,0xdf,0xef,0x10,0x00,0x05, - 0x00}}, - {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0, - 0x57,0x8e,0x57,0x67,0x20,0x00,0x01, - 0x01}}, - {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf1, - 0xff,0x86,0xff,0x0f,0x10,0x00,0x01, - 0x01}}, - {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a, - 0x02,0x86,0xff,0x0f,0x09,0x00,0x05, - 0x01}}, - {{0x76,0x56,0x9a,0x5b,0x89,0x28,0x10, - 0x1c,0x80,0x19,0x29,0x0b,0x00,0x05, - 0x00}} -#if 0 - {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f, - 0x93,0x86,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, - 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f, - 0x92,0x86,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, - 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f, - 0xe2,0x86,0xdf,0xef,0x10,0x00,0x05, - 0x00}}, - {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0, - 0x5a,0x8e,0x57,0x67,0x20,0x00,0x01, - 0x01}}, - {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf5, - 0x02,0x86,0xff,0x0f,0x10,0x00,0x01, - 0x01}}, - {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a, - 0x02,0x86,0xff,0x0f,0x09,0x00,0x05, - 0x01}}, - {{0x76,0x56,0x9a,0x5b,0x89,0x28,0x10, - 0x1c,0x80,0x19,0x29,0x0b,0x00,0x05, - 0x00}} -#endif -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_2[] = -{ - {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, - 0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x02, - 0x01}}, - {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, - 0xbe,0x82,0x44,0x43,0x01,0x00,0x02, - 0x01}}, - {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, - 0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x02, - 0x01}}, - {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, - 0xbe,0x82,0x44,0x43,0x01,0x00,0x02, - 0x01}}, - {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, - 0xff,0x83,0x85,0x84,0x11,0x00,0x02, - 0x01}}, - {{0xce,0x63,0x92,0x8e,0x1c,0x28,0xd4, - 0x3f,0x83,0x57,0x29,0x01,0x00,0x03, - 0x01}}, - {{0xce,0x7f,0x92,0x9c,0x0a,0x28,0xd4, - 0x93,0x87,0xff,0x29,0x21,0x00,0x07, - 0x01}}, - {{0xce,0x9f,0x92,0xac,0x1a,0x28,0x5a, - 0x13,0x87,0xff,0x29,0x29,0x00,0x07, - 0x01}}, - {{0xce,0xae,0x92,0xbc,0x0a,0x28,0x10, - 0x20,0x84,0x19,0x29,0x0f,0x00,0x03, - 0x00}} -#if 0 - {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a, - 0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03, - 0x00}}, - {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a, - 0xc2,0x86,0x5d,0x29,0x01,0x00,0x03, - 0x01}}, - {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a, - 0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03, - 0x00}}, - {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a, - 0xc2,0x86,0x5d,0x29,0x01,0x00,0x03, - 0x00}}, - {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9e, - 0x03,0x87,0xdf,0x29,0x01,0x00,0x03, - 0x00}}, - {{0xce,0x63,0x92,0x96,0x04,0x28,0xd4, - 0x3f,0x83,0x57,0x29,0x01,0x00,0x07, - 0x01}}, - {{0xce,0x7f,0x92,0xa4,0x12,0x28,0xd4, - 0x93,0x87,0xff,0x29,0x21,0x00,0x07, - 0x01}}, - {{0xce,0x9f,0x92,0xb4,0x02,0x28,0x5a, - 0x13,0x87,0xff,0x29,0x29,0x00,0x03, - 0x01}}, - {{0xce,0xae,0x92,0xbc,0x0a,0x28,0x10, - 0x20,0x84,0x19,0x29,0x0f,0x00,0x03, - 0x00}} -#endif -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_2_H[] = -{ - {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, - 0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x06, - 0x01}}, - {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, - 0xbe,0x82,0x44,0x43,0x01,0x00,0x06, - 0x01}}, - {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, - 0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x06, - 0x01}}, - {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, - 0xbe,0x82,0x44,0x43,0x01,0x00,0x06, - 0x01}}, - {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, - 0xff,0x83,0x85,0x84,0x11,0x00,0x06, - 0x01}}, - {{0x9c,0x31,0x80,0x5c,0x8a,0x28,0xd4, - 0x3f,0x83,0x57,0x29,0x01,0x00,0x06, - 0x01}}, - {{0x8e,0x3f,0x92,0x5c,0x0a,0x28,0xd4, - 0x93,0x87,0xff,0x29,0x21,0x00,0x06, - 0x01}}, - {{0x7e,0x4f,0x82,0x5c,0x0a,0x28,0x5a, - 0x13,0x87,0xff,0x29,0x29,0x00,0x06, - 0x01}}, - {{0x76,0x56,0x9a,0x64,0x92,0x28,0x10, - 0x20,0x84,0x19,0x29,0x0f,0x00,0x05, - 0x00}} -#if 0 - {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a, - 0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06, - 0x00}}, - {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a, - 0xc2,0x86,0x5d,0x29,0x01,0x00,0x06, - 0x00}}, - {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a, - 0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06, - 0x00}}, - {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a, - 0xc2,0x86,0x5d,0x29,0x01,0x00,0x06, - 0x00}}, - {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9e, - 0x03,0x87,0xdf,0x29,0x01,0x00,0x06, - 0x00}}, - {{0x9c,0x31,0x80,0x64,0x92,0x28,0xd4, - 0x3f,0x83,0x57,0x29,0x01,0x00,0x06, - 0x01}}, - {{0x8e,0x3f,0x92,0x64,0x12,0x28,0xd4, - 0x93,0x87,0xff,0x29,0x21,0x00,0x06, - 0x01}}, - {{0x7e,0x4f,0x82,0x64,0x12,0x28,0x5a, - 0x13,0x87,0xff,0x29,0x29,0x00,0x06, - 0x01}}, - {{0x76,0x56,0x9a,0x64,0x92,0x28,0x10, - 0x20,0x84,0x19,0x29,0x0f,0x00,0x05, - 0x00}} -#endif -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_1[] = -{ - {{0x83,0x4F,0x87,0x5B,0x13,0x06,0x3E, - 0xB3,0x86,0x8F,0x07,0x20,0x00,0x06, - 0x00}}, - {{0x83,0x4F,0x87,0x5B,0x13,0xD4,0x1F, - 0x81,0x84,0x5D,0xD5,0x10,0x00,0x06, - 0x00}}, - {{0x83,0x4F,0x87,0x5B,0x13,0x06,0x3E, - 0xB3,0x86,0x8F,0x07,0x20,0x00,0x06, - 0x00}}, - {{0x83,0x4F,0x87,0x5B,0x13,0xD4,0x1F, - 0x81,0x84,0x5D,0xD5,0x10,0x00,0x06, - 0x00}}, - {{0x83,0x4F,0x87,0x5B,0x13,0x56,0xBA, - 0x03,0x86,0xDF,0x57,0x00,0x00,0x06, - 0x00}}, - {{0x97,0x63,0x9B,0x6F,0x07,0xCE,0xF0, - 0x7B,0x8E,0x57,0xCF,0x20,0x00,0x02, - 0x01}}, - {{0xB3,0x7F,0x97,0x8B,0x83,0x76,0xF5, - 0x23,0x86,0xFF,0x77,0x10,0x00,0x06, - 0x01}}, - {{0xD3,0x9F,0x97,0xAB,0x03,0x76,0x5A, - 0x23,0x86,0xFF,0x77,0x09,0x00,0x03, - 0x01}}, - {{0xE2,0xAE,0x86,0xBA,0x92,0x90,0x10, - 0x3D,0x80,0x19,0x91,0x0F,0x00,0x03, - 0x00}}, - {{0xFB,0xC7,0x9F,0xD3,0x8B,0x26,0x11, - 0xD3,0x86,0xAF,0x27,0x3F,0x00,0x07, - 0x00}} -#if 0 - {{0x83,0x4f,0x87,0x51,0x09,0xc0,0x1f, - 0x90,0x84,0x8f,0xc1,0x30,0x00,0x06, - 0x00}}, - {{0x83,0x4f,0x87,0x51,0x09,0x8e,0x1f, - 0x5e,0x82,0x5d,0x8f,0x10,0x00,0x06, - 0x00}}, - {{0x83,0x4f,0x87,0x51,0x09,0xc0,0x1f, - 0x90,0x84,0x8f,0xc1,0x30,0x00,0x06, - 0x00}}, - {{0x83,0x4f,0x87,0x51,0x09,0x8e,0x1f, - 0x5e,0x82,0x5d,0x8f,0x10,0x00,0x06, - 0x00}}, - {{0x83,0x4f,0x87,0x51,0x09,0x10,0x3e, - 0xe0,0x84,0xdf,0x11,0x00,0x00,0x06, - 0x00}}, - {{0x97,0x63,0x9b,0x65,0x1d,0x88,0xf0, - 0x58,0x8c,0x57,0x89,0x20,0x00,0x06, - 0x01}}, - {{0xb3,0x7f,0x97,0x81,0x99,0x30,0xf5, - 0x00,0x84,0xff,0x31,0x10,0x00,0x02, - 0x01}}, - {{0xd3,0x9f,0x97,0xa1,0x19,0x30,0x5a, - 0x00,0x84,0xff,0x31,0x09,0x00,0x07, - 0x01}}, - {{0xe2,0xae,0x86,0xb0,0x88,0x4a,0x10, - 0x1a,0x8e,0x19,0x4b,0x2f,0x00,0x03, - 0x00}}, - {{0xfb,0xc7,0x9f,0xc9,0x81,0xe0,0x10, - 0xb0,0x84,0xaf,0xe1,0x2f,0x00,0x07, - 0x00}} -#endif -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_1_H[] = -{ - {{0x5B,0x27,0x9F,0x33,0x0B,0x06,0x2E, - 0xB3,0x86,0x8F,0x07,0x20,0x00,0x01, - 0x00}}, - {{0x5B,0x27,0x9F,0x29,0x01,0x8E,0x1F, - 0x81,0x84,0x5D,0xD5,0x10,0x00,0x06, - 0x00}}, - {{0x5B,0x27,0x9F,0x33,0x0B,0x06,0x2E, - 0xB3,0x86,0x8F,0x07,0x20,0x00,0x01, - 0x00}}, - {{0x83,0x4F,0x87,0x5B,0x13,0xD4,0x1F, - 0x81,0x84,0x5D,0xD5,0x10,0x00,0x06, - 0x00}}, - {{0x5B,0x27,0x9F,0x33,0x0B,0x56,0xBA, - 0x03,0x86,0xDF,0x57,0x00,0x00,0x01, - 0x00}}, - {{0x65,0x31,0x89,0x3D,0x95,0xCE,0xF0, - 0x7B,0x8E,0x57,0xCF,0x20,0x00,0x01, - 0x01}}, - {{0x73,0x3F,0x97,0x4B,0x83,0x76,0xF5, - 0x23,0x86,0xFF,0x77,0x10,0x00,0x05, - 0x01}}, - {{0xD3,0x9F,0x97,0xAB,0x03,0x76,0x5A, - 0x23,0x86,0xFF,0x77,0x09,0x00,0x03, - 0x01}}, - {{0xE2,0xAE,0x86,0xBA,0x92,0x90,0x10, - 0x3D,0x80,0x19,0x91,0x0F,0x00,0x03, - 0x00}}, - {{0x97,0x63,0x9B,0x6F,0x07,0xE0,0x10, - 0xB0,0x84,0xAF,0xE1,0x2F,0x00,0x06, - 0x00}} -#if 0 - {{0x5b,0x27,0x9f,0x29,0x01,0xc0,0x1f, - 0x90,0x84,0x8f,0xc1,0x30,0x00,0x01, - 0x00}}, - {{0x5b,0x27,0x9f,0x29,0x01,0x8e,0x1f, - 0x5e,0x82,0x5d,0x8f,0x10,0x00,0x01, - 0x00}}, - {{0x5b,0x27,0x9f,0x29,0x01,0xc0,0x1f, - 0x90,0x84,0x8f,0xc1,0x30,0x00,0x01, - 0x00}}, - {{0x5b,0x27,0x9f,0x29,0x01,0x8e,0x1f, - 0x5e,0x82,0x5d,0x8f,0x10,0x00,0x01, - 0x00}}, - {{0x5b,0x27,0x9f,0x29,0x01,0x10,0x3e, - 0xe0,0x84,0xdf,0x11,0x00,0x00,0x01, - 0x00}}, - {{0x65,0x31,0x89,0x33,0x8b,0x88,0xf0, - 0x58,0x8c,0x57,0x89,0x20,0x00,0x01, - 0x01}}, - {{0x73,0x3f,0x97,0x41,0x99,0x30,0xf5, - 0x00,0x84,0xff,0x31,0x10,0x00,0x01, - 0x01}}, - {{0x83,0x4f,0x87,0x51,0x09,0x30,0x5a, - 0x00,0x84,0xff,0x31,0x09,0x00,0x06, - 0x01}}, - {{0x8a,0x56,0x8e,0x58,0x10,0x4a,0x10, - 0x1a,0x8e,0x19,0x4b,0x2f,0x00,0x06, - 0x00}}, - {{0x97,0x63,0x9b,0x65,0x1d,0xe0,0x10, - 0xb0,0x84,0xaf,0xe1,0x2f,0x00,0x06, - 0x00}} -#endif -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_2[] = -{ - {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97, - 0x43,0x86,0xDB,0xDA,0x11,0x00,0x07, - 0x01}}, - {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97, - 0x2A,0x8D,0xC2,0xC1,0x11,0x00,0x07, - 0x01}}, - {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97, - 0x43,0x86,0xDB,0xDA,0x11,0x00,0x07, - 0x01}}, - {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97, - 0x2A,0x8D,0xC2,0xC1,0x11,0x00,0x07, - 0x01}}, - {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x9F, - 0x6B,0x8E,0x03,0x02,0x01,0x00,0x07, - 0x01}}, - {{0xFB,0x63,0x9F,0xA1,0x99,0x26,0xD5, - 0xA7,0x8A,0xBF,0xBE,0x01,0x00,0x07, - 0x01}}, - {{0xFB,0x7F,0x9F,0xAF,0x87,0x26,0xDD, - 0xFB,0x8E,0x13,0x12,0x31,0x00,0x03, - 0x01}}, - {{0xFB,0x9F,0x9F,0xBF,0x97,0x26,0x5B, - 0x7B,0x8E,0xFF,0x27,0x39,0x00,0x03, - 0x01}}, - {{0xFB,0xAE,0x9F,0xC6,0x9E,0x26,0x11, - 0x88,0x8B,0x19,0x27,0x1F,0x00,0x03, - 0x00}}, - {{0xFB,0xC7,0x9F,0xD3,0x8B,0x26,0x11, - 0xD3,0x86,0xAF,0x27,0x3F,0x00,0x07, - 0x00}} -#if 0 - {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96, - 0x20,0x84,0xb9,0xb8,0x01,0x00,0x07, - 0x01}}, - {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96, - 0x07,0x8b,0xa0,0x9f,0x01,0x00,0x07, - 0x01}}, - {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96, - 0x20,0x84,0xb9,0xb8,0x01,0x00,0x07, - 0x01}}, - {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96, - 0x07,0x8b,0xa0,0x9f,0x01,0x00,0x07, - 0x01}}, - {{0xfb,0x88,0x87,0x90,0x08,0xe0,0x96, - 0x48,0x8c,0xe1,0xe0,0x11,0x00,0x07, - 0x01}}, - {{0xfb,0x63,0x9f,0x9a,0x92,0xe0,0xd4, - 0x9b,0x8f,0x9d,0x9c,0x21,0x00,0x07, - 0x01}}, - {{0xfb,0x7f,0x9f,0xa8,0x80,0xe0,0xd4, - 0xef,0x83,0xff,0xe1,0x21,0x00,0x03, - 0x01}}, - {{0xfb,0x9f,0x9f,0xb8,0x90,0xe0,0x5a, - 0x6f,0x83,0xff,0xe1,0x29,0x00,0x03, - 0x01}}, - {{0xfb,0xae,0x9f,0xbf,0x97,0xe0,0x10, - 0x7c,0x80,0x19,0xe1,0x0f,0x00,0x03, - 0x00}}, - {{0xfb,0xc7,0x9f,0xc9,0x84,0xe0,0x10, - 0xc7,0x8b,0xaf,0xe1,0x0f,0x00,0x07, - 0x00}} -#endif -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_2_H[] = -{ - {{0xD3,0x5F,0x9E,0x6F,0x07,0x26,0x97, - 0x43,0x86,0xDB,0xDA,0x11,0x00,0x02, - 0x01}}, - {{0xD3,0x27,0x97,0x6F,0x07,0x26,0x97, - 0x6B,0x8E,0x83,0x82,0x01,0x00,0x03, - 0x01}}, - {{0xD3,0x5F,0x9E,0x6F,0x07,0x26,0x97, - 0x43,0x86,0xDB,0xDA,0x11,0x00,0x02, - 0x01}}, - {{0xD3,0x27,0x97,0x6F,0x07,0x26,0x97, - 0x07,0x8B,0xA0,0x9F,0x01,0x00,0x02, - 0x01}}, - {{0xD3,0x27,0x97,0x6F,0x07,0x26,0x97, - 0x6B,0x8E,0x83,0x82,0x01,0x00,0x03, - 0x01}}, - {{0xC9,0x31,0x8D,0x6F,0x07,0x26,0xD5, - 0xA7,0x8A,0xBF,0xBE,0x01,0x00,0x03, - 0x01}}, - {{0xBB,0x3F,0x9F,0x6F,0x87,0x26,0xDD, - 0xFB,0x8E,0x13,0x12,0x31,0x00,0x02, - 0x01}}, - {{0xAB,0x4F,0x8F,0x68,0x80,0xE0,0x5A, - 0x6F,0x83,0xFF,0xE1,0x29,0x00,0x02, - 0x01}}, - {{0xA3,0x56,0x87,0x67,0x9F,0xE0,0x10, - 0x7C,0x80,0x19,0xE1,0x0F,0x00,0x06, - 0x00}}, - {{0x97,0x63,0x9B,0x68,0x00,0xE0,0x10, - 0xC7,0x8B,0xAF,0xE1,0x0F,0x00,0x02, - 0x00}} -#if 0 - {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96, - 0x20,0x84,0xb9,0xb8,0x01,0x00,0x02, - 0x01}}, - {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96, - 0x07,0x8b,0xa0,0x9f,0x01,0x00,0x02, - 0x01}}, - {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96, - 0x20,0x84,0xb9,0xb8,0x01,0x00,0x02, - 0x01}}, - {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96, - 0x07,0x8b,0xa0,0x9f,0x01,0x00,0x02, - 0x01}}, - {{0xd3,0x60,0x9f,0x68,0x00,0xe0,0x96, - 0x48,0x8c,0xe1,0xe0,0x11,0x00,0x02, - 0x01}}, - {{0xc9,0x31,0x8d,0x68,0x00,0xe0,0xd4, - 0x9b,0x8f,0x9d,0x9c,0x21,0x00,0x03, - 0x01}}, - {{0xbb,0x3f,0x9f,0x68,0x80,0xe0,0xd4, - 0xef,0x83,0xff,0xe1,0x21,0x00,0x02, - 0x01}}, - {{0xab,0x4f,0x8f,0x68,0x80,0xe0,0x5a, - 0x6f,0x83,0xff,0xe1,0x29,0x00,0x02, - 0x01}}, - {{0xa3,0x56,0x87,0x67,0x9f,0xe0,0x10, - 0x7c,0x80,0x19,0xe1,0x0f,0x00,0x06, - 0x00}}, - {{0x97,0x63,0x9b,0x68,0x00,0xe0,0x10, - 0xc7,0x8b,0xaf,0xe1,0x0f,0x00,0x02, - 0x00}} -#endif -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1XXXxXXX_1[] = -{ - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, - {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, - 0x01}}, - {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x02, - 0x01}}, - {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, - 0x00,0x84,0xff,0x29,0x09,0x00,0x07, - 0x01}}, - {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x07, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1XXXxXXX_1_H[] = -{ - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, - {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x01, - 0x01}}, - {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01}} -}; - - /* CRT1 CRTC for Chrontel TV slave modes */ -static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1UNTSC[] = -{ +static const struct SiS_LVDSCRT1Data SiS310_CHTVCRT1UNTSC[] = +{ {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, 0x00 }}, @@ -2546,7 +1132,7 @@ static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1UNTSC[] = 0x01}} }; -static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1ONTSC[] = +static const struct SiS_LVDSCRT1Data SiS310_CHTVCRT1ONTSC[] = { {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e, 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, @@ -2571,8 +1157,8 @@ static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1ONTSC[] = 0x01 }} }; -static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1UPAL[] = -{ +static const struct SiS_LVDSCRT1Data SiS310_CHTVCRT1UPAL[] = +{ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, 0x00 }}, @@ -2596,7 +1182,7 @@ static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1UPAL[] = 0x01}} }; -static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1OPAL[] = +static const struct SiS_LVDSCRT1Data SiS310_CHTVCRT1OPAL[] = { {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, @@ -2621,8 +1207,7 @@ static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1OPAL[] = 0x01 }} }; - -static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = +static const struct SiS_CHTVRegData SiS310_CHTVReg_UNTSC[] = { {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -2642,7 +1227,7 @@ static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = for PAL-M and PAL-N all above is corrected. */ -static const SiS_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = +static const struct SiS_CHTVRegData SiS310_CHTVReg_ONTSC[] = { {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -2653,7 +1238,7 @@ static const SiS_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = {{0xed,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x9f,0xc1,0x0c,0x00}} }; -static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = +static const struct SiS_CHTVRegData SiS310_CHTVReg_UPAL[] = { {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -2664,7 +1249,7 @@ static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x20,0x3e,0xe4,0x22,0x00}} }; -static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = +static const struct SiS_CHTVRegData SiS310_CHTVReg_OPAL[] = { {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -2675,7 +1260,7 @@ static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x25,0x8c,0xb2,0x2a,0x00}} }; -static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALM[] = +static const struct SiS_CHTVRegData SiS310_CHTVReg_UPALM[] = { {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -2691,7 +1276,7 @@ static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALM[] = #endif }; -static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALM[] = +static const struct SiS_CHTVRegData SiS310_CHTVReg_OPALM[] = { {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -2707,7 +1292,7 @@ static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALM[] = #endif }; -static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALN[] = +static const struct SiS_CHTVRegData SiS310_CHTVReg_UPALN[] = { {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, @@ -2723,7 +1308,7 @@ static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALN[] = #endif }; -static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALN[] = +static const struct SiS_CHTVRegData SiS310_CHTVReg_OPALN[] = { {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, @@ -2739,16 +1324,16 @@ static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALN[] = #endif }; -static const UCHAR SiS310_CHTVVCLKUNTSC[] = {0x41,0x41,0x41,0x41,0x42,0x46,0x53}; -static const UCHAR SiS310_CHTVVCLKONTSC[] = {0x48,0x48,0x48,0x48,0x45,0x43,0x51}; +static const unsigned char SiS310_CHTVVCLKUNTSC[] = { 0x41,0x41,0x41,0x41,0x42,0x46,0x53 }; +static const unsigned char SiS310_CHTVVCLKONTSC[] = { 0x48,0x48,0x48,0x48,0x45,0x43,0x51 }; -static const UCHAR SiS310_CHTVVCLKUPAL[] = {0x47,0x47,0x47,0x47,0x48,0x4a,0x54}; -static const UCHAR SiS310_CHTVVCLKOPAL[] = {0x47,0x47,0x47,0x47,0x48,0x4f,0x52}; +static const unsigned char SiS310_CHTVVCLKUPAL[] = { 0x47,0x47,0x47,0x47,0x48,0x4a,0x54 }; +static const unsigned char SiS310_CHTVVCLKOPAL[] = { 0x47,0x47,0x47,0x47,0x48,0x4f,0x52 }; -static const UCHAR SiS310_CHTVVCLKUPALM[] = {0x41,0x41,0x41,0x41,0x42,0x46,0x53}; -static const UCHAR SiS310_CHTVVCLKOPALM[] = {0x48,0x48,0x48,0x48,0x45,0x43,0x51}; +static const unsigned char SiS310_CHTVVCLKUPALM[] = { 0x41,0x41,0x41,0x41,0x42,0x46,0x53 }; +static const unsigned char SiS310_CHTVVCLKOPALM[] = { 0x48,0x48,0x48,0x48,0x45,0x43,0x51 }; -static const UCHAR SiS310_CHTVVCLKUPALN[] = {0x47,0x47,0x47,0x47,0x48,0x4a,0x54}; -static const UCHAR SiS310_CHTVVCLKOPALN[] = {0x47,0x47,0x47,0x47,0x48,0x4f,0x52}; +static const unsigned char SiS310_CHTVVCLKUPALN[] = { 0x47,0x47,0x47,0x47,0x48,0x4a,0x54 }; +static const unsigned char SiS310_CHTVVCLKOPALN[] = { 0x47,0x47,0x47,0x47,0x48,0x4f,0x52 }; diff --git a/drivers/video/sis/Makefile b/drivers/video/sis/Makefile index aaed8c2b4a64d..f7c0046e5b1d1 100644 --- a/drivers/video/sis/Makefile +++ b/drivers/video/sis/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_FB_SIS) += sisfb.o -sisfb-objs := sis_main.o sis_accel.o init.o init301.o +sisfb-objs := sis_main.o sis_accel.o init.o init301.o initextlfb.o diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c index ecfd72178dbb3..2ab3868efde30 100644 --- a/drivers/video/sis/init.c +++ b/drivers/video/sis/init.c @@ -2,11 +2,12 @@ /* $XdotOrg$ */ /* * Mode initializing code (CRT1 section) for - * for SiS 300/305/540/630/730 and - * SiS 315/550/650/M650/651/661FX/M661FX/740/741(GX)/M741/330/660/M660/760/M760 - * (Universal module for Linux kernel framebuffer and XFree86 4.x) + * for SiS 300/305/540/630/730, + * SiS 315/550/[M]650/651/[M]661[FGM]X/[M]74x[GX]/330/[M]76x[GX], + * XGI Volari V3XT/V5/V8, Z7 + * (Universal module for Linux kernel framebuffer and X.org/XFree86 4.x) * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -53,17 +54,12 @@ * * Formerly based on non-functional code-fragements for 300 series by SiS, Inc. * Used by permission. - * - * TW says: This code looks awful, I know. But please don't do anything about - * this otherwise debugging will be hell. - * The code is extremely fragile as regards the different chipsets, different - * video bridges and combinations thereof. If anything is changed, extreme - * care has to be taken that that change doesn't break it for other chipsets, - * bridges or combinations thereof. - * All comments in this file are by me, regardless if they are marked TW or not. - * */ - + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "init.h" #ifdef SIS300 @@ -84,24 +80,13 @@ #if defined(SIS300) || defined(SIS315H) static void -InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +InitCommonPointer(struct SiS_Private *SiS_Pr) { + SiS_Pr->SiS_SModeIDTable = SiS_SModeIDTable; SiS_Pr->SiS_StResInfo = SiS_StResInfo; SiS_Pr->SiS_ModeResInfo = SiS_ModeResInfo; SiS_Pr->SiS_StandTable = SiS_StandTable; - SiS_Pr->SiS_NTSCPhase = SiS_NTSCPhase; - SiS_Pr->SiS_PALPhase = SiS_PALPhase; - SiS_Pr->SiS_NTSCPhase2 = SiS_NTSCPhase2; - SiS_Pr->SiS_PALPhase2 = SiS_PALPhase2; - SiS_Pr->SiS_PALMPhase = SiS_PALMPhase; - SiS_Pr->SiS_PALNPhase = SiS_PALNPhase; - SiS_Pr->SiS_PALMPhase2 = SiS_PALMPhase2; - SiS_Pr->SiS_PALNPhase2 = SiS_PALNPhase2; - SiS_Pr->SiS_SpecialPhase = SiS_SpecialPhase; - SiS_Pr->SiS_SpecialPhaseM = SiS_SpecialPhaseM; - SiS_Pr->SiS_SpecialPhaseJ = SiS_SpecialPhaseJ; - SiS_Pr->SiS_NTSCTiming = SiS_NTSCTiming; SiS_Pr->SiS_PALTiming = SiS_PALTiming; SiS_Pr->SiS_HiTVSt1Timing = SiS_HiTVSt1Timing; @@ -137,6 +122,7 @@ InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_Pr->SiS_ExtLCD1280x768_2Data = SiS_ExtLCD1280x768_2Data; SiS_Pr->SiS_LCD1280x800Data = SiS_LCD1280x800Data; SiS_Pr->SiS_LCD1280x800_2Data = SiS_LCD1280x800_2Data; + SiS_Pr->SiS_LCD1280x854Data = SiS_LCD1280x854Data; SiS_Pr->SiS_LCD1280x960Data = SiS_LCD1280x960Data; SiS_Pr->SiS_StLCD1400x1050Data = SiS_StLCD1400x1050Data; SiS_Pr->SiS_ExtLCD1400x1050Data = SiS_ExtLCD1400x1050Data; @@ -145,67 +131,30 @@ InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_Pr->SiS_ExtLCD1600x1200Data = SiS_ExtLCD1600x1200Data; SiS_Pr->SiS_NoScaleData = SiS_NoScaleData; - SiS_Pr->SiS_LVDS320x480Data_1 = SiS_LVDS320x480Data_1; + SiS_Pr->SiS_LVDS320x240Data_1 = SiS_LVDS320x240Data_1; + SiS_Pr->SiS_LVDS320x240Data_2 = SiS_LVDS320x240Data_2; + SiS_Pr->SiS_LVDS640x480Data_1 = SiS_LVDS640x480Data_1; SiS_Pr->SiS_LVDS800x600Data_1 = SiS_LVDS800x600Data_1; - SiS_Pr->SiS_LVDS800x600Data_2 = SiS_LVDS800x600Data_2; - SiS_Pr->SiS_LVDS1024x768Data_1 = SiS_LVDS1024x768Data_1; - SiS_Pr->SiS_LVDS1024x768Data_2 = SiS_LVDS1024x768Data_2; - SiS_Pr->SiS_LVDS1280x1024Data_1 = SiS_LVDS1280x1024Data_1; - SiS_Pr->SiS_LVDS1280x1024Data_2 = SiS_LVDS1280x1024Data_2; - SiS_Pr->SiS_LVDS1400x1050Data_1 = SiS_LVDS1400x1050Data_1; - SiS_Pr->SiS_LVDS1400x1050Data_2 = SiS_LVDS1400x1050Data_2; - SiS_Pr->SiS_LVDS1600x1200Data_1 = SiS_LVDS1600x1200Data_1; - SiS_Pr->SiS_LVDS1600x1200Data_2 = SiS_LVDS1600x1200Data_2; - SiS_Pr->SiS_LVDS1280x768Data_1 = SiS_LVDS1280x768Data_1; - SiS_Pr->SiS_LVDS1280x768Data_2 = SiS_LVDS1280x768Data_2; SiS_Pr->SiS_LVDS1024x600Data_1 = SiS_LVDS1024x600Data_1; - SiS_Pr->SiS_LVDS1024x600Data_2 = SiS_LVDS1024x600Data_2; - SiS_Pr->SiS_LVDS1152x768Data_1 = SiS_LVDS1152x768Data_1; - SiS_Pr->SiS_LVDS1152x768Data_2 = SiS_LVDS1152x768Data_2; - SiS_Pr->SiS_LVDSXXXxXXXData_1 = SiS_LVDSXXXxXXXData_1; - SiS_Pr->SiS_LVDS1280x960Data_1 = SiS_LVDS1280x960Data_1; - SiS_Pr->SiS_LVDS1280x960Data_2 = SiS_LVDS1280x960Data_2; - SiS_Pr->SiS_LVDS640x480Data_1 = SiS_LVDS640x480Data_1; - SiS_Pr->SiS_LVDS1280x960Data_1 = SiS_LVDS1280x1024Data_1; - SiS_Pr->SiS_LVDS1280x960Data_2 = SiS_LVDS1280x1024Data_2; - SiS_Pr->SiS_LVDS640x480Data_1 = SiS_LVDS640x480Data_1; - SiS_Pr->SiS_LVDS640x480Data_2 = SiS_LVDS640x480Data_2; - - SiS_Pr->SiS_LVDS848x480Data_1 = SiS_LVDS848x480Data_1; - SiS_Pr->SiS_LVDS848x480Data_2 = SiS_LVDS848x480Data_2; - SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS_LVDSBARCO1024Data_1; - SiS_Pr->SiS_LVDSBARCO1024Data_2 = SiS_LVDSBARCO1024Data_2; - SiS_Pr->SiS_LVDSBARCO1366Data_1 = SiS_LVDSBARCO1366Data_1; - SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS_LVDSBARCO1366Data_2; + SiS_Pr->SiS_LVDS1024x768Data_1 = SiS_LVDS1024x768Data_1; - SiS_Pr->SiS_LVDSCRT11280x768_1 = SiS_LVDSCRT11280x768_1; + SiS_Pr->SiS_LVDSCRT1320x240_1 = SiS_LVDSCRT1320x240_1; + SiS_Pr->SiS_LVDSCRT1320x240_2 = SiS_LVDSCRT1320x240_2; + SiS_Pr->SiS_LVDSCRT1320x240_2_H = SiS_LVDSCRT1320x240_2_H; + SiS_Pr->SiS_LVDSCRT1320x240_3 = SiS_LVDSCRT1320x240_3; + SiS_Pr->SiS_LVDSCRT1320x240_3_H = SiS_LVDSCRT1320x240_3_H; + SiS_Pr->SiS_LVDSCRT1640x480_1 = SiS_LVDSCRT1640x480_1; + SiS_Pr->SiS_LVDSCRT1640x480_1_H = SiS_LVDSCRT1640x480_1_H; +#if 0 SiS_Pr->SiS_LVDSCRT11024x600_1 = SiS_LVDSCRT11024x600_1; - SiS_Pr->SiS_LVDSCRT11152x768_1 = SiS_LVDSCRT11152x768_1; - SiS_Pr->SiS_LVDSCRT11280x768_1_H = SiS_LVDSCRT11280x768_1_H; SiS_Pr->SiS_LVDSCRT11024x600_1_H = SiS_LVDSCRT11024x600_1_H; - SiS_Pr->SiS_LVDSCRT11152x768_1_H = SiS_LVDSCRT11152x768_1_H; - SiS_Pr->SiS_LVDSCRT11280x768_2 = SiS_LVDSCRT11280x768_2; SiS_Pr->SiS_LVDSCRT11024x600_2 = SiS_LVDSCRT11024x600_2; - SiS_Pr->SiS_LVDSCRT11152x768_2 = SiS_LVDSCRT11152x768_2; - SiS_Pr->SiS_LVDSCRT11280x768_2_H = SiS_LVDSCRT11280x768_2_H; SiS_Pr->SiS_LVDSCRT11024x600_2_H = SiS_LVDSCRT11024x600_2_H; - SiS_Pr->SiS_LVDSCRT11152x768_2_H = SiS_LVDSCRT11152x768_2_H; - SiS_Pr->SiS_LVDSCRT1320x480_1 = SiS_LVDSCRT1320x480_1; - SiS_Pr->SiS_LVDSCRT1640x480_1 = SiS_LVDSCRT1640x480_1; - SiS_Pr->SiS_LVDSCRT1640x480_1_H = SiS_LVDSCRT1640x480_1_H; - SiS_Pr->SiS_LVDSCRT1640x480_2 = SiS_LVDSCRT1640x480_2; - SiS_Pr->SiS_LVDSCRT1640x480_2_H = SiS_LVDSCRT1640x480_2_H; - SiS_Pr->SiS_LVDSCRT1640x480_3 = SiS_LVDSCRT1640x480_3; - SiS_Pr->SiS_LVDSCRT1640x480_3_H = SiS_LVDSCRT1640x480_3_H; +#endif SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData; SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData; - SiS_Pr->SiS_CHTVUNTSCDesData = SiS_CHTVUNTSCDesData; - SiS_Pr->SiS_CHTVONTSCDesData = SiS_CHTVONTSCDesData; - SiS_Pr->SiS_CHTVUPALDesData = SiS_CHTVUPALDesData; - SiS_Pr->SiS_CHTVOPALDesData = SiS_CHTVOPALDesData; - SiS_Pr->SiS_PanelMinLVDS = Panel_800x600; /* lowest value LVDS/LCDA */ SiS_Pr->SiS_PanelMin301 = Panel_1024x768; /* lowest value 301 */ } @@ -213,50 +162,24 @@ InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) #ifdef SIS300 static void -InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +InitTo300Pointer(struct SiS_Private *SiS_Pr) { - InitCommonPointer(SiS_Pr, HwInfo); + InitCommonPointer(SiS_Pr); - SiS_Pr->SiS_SModeIDTable = SiS300_SModeIDTable; SiS_Pr->SiS_VBModeIDTable = SiS300_VBModeIDTable; SiS_Pr->SiS_EModeIDTable = SiS300_EModeIDTable; SiS_Pr->SiS_RefIndex = SiS300_RefIndex; SiS_Pr->SiS_CRT1Table = SiS300_CRT1Table; - if(HwInfo->jChipType == SIS_300) { - SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_300; /* 300 */ + if(SiS_Pr->ChipType == SIS_300) { + SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_300; /* 300 */ } else { - SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_630; /* 630, 730 */ + SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_630; /* 630, 730 */ } SiS_Pr->SiS_VCLKData = SiS300_VCLKData; - SiS_Pr->SiS_VBVCLKData = (SiS_VBVCLKDataStruct *)SiS300_VCLKData; + SiS_Pr->SiS_VBVCLKData = (struct SiS_VBVCLKData *)SiS300_VCLKData; SiS_Pr->SiS_SR15 = SiS300_SR15; -#ifdef LINUX_KERNEL - SiS_Pr->pSiS_SR07 = &SiS300_SR07; - SiS_Pr->SiS_CR40 = SiS300_CR40; - SiS_Pr->SiS_CR49 = SiS300_CR49; - SiS_Pr->pSiS_SR1F = &SiS300_SR1F; - SiS_Pr->pSiS_SR21 = &SiS300_SR21; - SiS_Pr->pSiS_SR22 = &SiS300_SR22; - SiS_Pr->pSiS_SR23 = &SiS300_SR23; - SiS_Pr->pSiS_SR24 = &SiS300_SR24; - SiS_Pr->SiS_SR25 = SiS300_SR25; - SiS_Pr->pSiS_SR31 = &SiS300_SR31; - SiS_Pr->pSiS_SR32 = &SiS300_SR32; - SiS_Pr->pSiS_SR33 = &SiS300_SR33; - SiS_Pr->pSiS_CRT2Data_1_2 = &SiS300_CRT2Data_1_2; - SiS_Pr->pSiS_CRT2Data_4_D = &SiS300_CRT2Data_4_D; - SiS_Pr->pSiS_CRT2Data_4_E = &SiS300_CRT2Data_4_E; - SiS_Pr->pSiS_CRT2Data_4_10 = &SiS300_CRT2Data_4_10; - SiS_Pr->pSiS_RGBSenseData = &SiS300_RGBSenseData; - SiS_Pr->pSiS_VideoSenseData = &SiS300_VideoSenseData; - SiS_Pr->pSiS_YCSenseData = &SiS300_YCSenseData; - SiS_Pr->pSiS_RGBSenseData2 = &SiS300_RGBSenseData2; - SiS_Pr->pSiS_VideoSenseData2 = &SiS300_VideoSenseData2; - SiS_Pr->pSiS_YCSenseData2 = &SiS300_YCSenseData2; -#endif - SiS_Pr->SiS_PanelDelayTbl = SiS300_PanelDelayTbl; SiS_Pr->SiS_PanelDelayTblLVDS = SiS300_PanelDelayTbl; @@ -266,11 +189,8 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_Pr->SiS_St2LCD1280x1024Data = SiS300_St2LCD1280x1024Data; SiS_Pr->SiS_CRT2Part2_1024x768_1 = SiS300_CRT2Part2_1024x768_1; - SiS_Pr->SiS_CRT2Part2_1280x1024_1 = SiS300_CRT2Part2_1280x1024_1; SiS_Pr->SiS_CRT2Part2_1024x768_2 = SiS300_CRT2Part2_1024x768_2; - SiS_Pr->SiS_CRT2Part2_1280x1024_2 = SiS300_CRT2Part2_1280x1024_2; SiS_Pr->SiS_CRT2Part2_1024x768_3 = SiS300_CRT2Part2_1024x768_3; - SiS_Pr->SiS_CRT2Part2_1280x1024_3 = SiS300_CRT2Part2_1280x1024_3; SiS_Pr->SiS_CHTVUPALData = SiS300_CHTVUPALData; SiS_Pr->SiS_CHTVOPALData = SiS300_CHTVOPALData; @@ -280,64 +200,16 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_Pr->SiS_CHTVOPALNData = SiS300_CHTVOPALData; /* not supported on 300 series */ SiS_Pr->SiS_CHTVSOPALData = SiS300_CHTVSOPALData; - SiS_Pr->SiS_PanelType00_1 = SiS300_PanelType00_1; - SiS_Pr->SiS_PanelType01_1 = SiS300_PanelType01_1; - SiS_Pr->SiS_PanelType02_1 = SiS300_PanelType02_1; - SiS_Pr->SiS_PanelType03_1 = SiS300_PanelType03_1; - SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1; - SiS_Pr->SiS_PanelType05_1 = SiS300_PanelType05_1; - SiS_Pr->SiS_PanelType06_1 = SiS300_PanelType06_1; - SiS_Pr->SiS_PanelType07_1 = SiS300_PanelType07_1; - SiS_Pr->SiS_PanelType08_1 = SiS300_PanelType08_1; - SiS_Pr->SiS_PanelType09_1 = SiS300_PanelType09_1; - SiS_Pr->SiS_PanelType0a_1 = SiS300_PanelType0a_1; - SiS_Pr->SiS_PanelType0b_1 = SiS300_PanelType0b_1; - SiS_Pr->SiS_PanelType0c_1 = SiS300_PanelType0c_1; - SiS_Pr->SiS_PanelType0d_1 = SiS300_PanelType0d_1; - SiS_Pr->SiS_PanelType0e_1 = SiS300_PanelType0e_1; - SiS_Pr->SiS_PanelType0f_1 = SiS300_PanelType0f_1; - SiS_Pr->SiS_PanelType00_2 = SiS300_PanelType00_2; - SiS_Pr->SiS_PanelType01_2 = SiS300_PanelType01_2; - SiS_Pr->SiS_PanelType02_2 = SiS300_PanelType02_2; - SiS_Pr->SiS_PanelType03_2 = SiS300_PanelType03_2; - SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2; - SiS_Pr->SiS_PanelType05_2 = SiS300_PanelType05_2; - SiS_Pr->SiS_PanelType06_2 = SiS300_PanelType06_2; - SiS_Pr->SiS_PanelType07_2 = SiS300_PanelType07_2; - SiS_Pr->SiS_PanelType08_2 = SiS300_PanelType08_2; - SiS_Pr->SiS_PanelType09_2 = SiS300_PanelType09_2; - SiS_Pr->SiS_PanelType0a_2 = SiS300_PanelType0a_2; - SiS_Pr->SiS_PanelType0b_2 = SiS300_PanelType0b_2; - SiS_Pr->SiS_PanelType0c_2 = SiS300_PanelType0c_2; - SiS_Pr->SiS_PanelType0d_2 = SiS300_PanelType0d_2; - SiS_Pr->SiS_PanelType0e_2 = SiS300_PanelType0e_2; - SiS_Pr->SiS_PanelType0f_2 = SiS300_PanelType0f_2; - SiS_Pr->SiS_PanelTypeNS_1 = SiS300_PanelTypeNS_1; - SiS_Pr->SiS_PanelTypeNS_2 = SiS300_PanelTypeNS_2; - - if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { - SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1a; - SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2a; - } - if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { - SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1b; - SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2b; - } - - SiS_Pr->SiS_LVDSCRT1800x600_1 = SiS300_LVDSCRT1800x600_1; - SiS_Pr->SiS_LVDSCRT1800x600_1_H = SiS300_LVDSCRT1800x600_1_H; - SiS_Pr->SiS_LVDSCRT1800x600_2 = SiS300_LVDSCRT1800x600_2; - SiS_Pr->SiS_LVDSCRT1800x600_2_H = SiS300_LVDSCRT1800x600_2_H; - SiS_Pr->SiS_LVDSCRT11024x768_1 = SiS300_LVDSCRT11024x768_1; - SiS_Pr->SiS_LVDSCRT11024x768_1_H = SiS300_LVDSCRT11024x768_1_H; - SiS_Pr->SiS_LVDSCRT11024x768_2 = SiS300_LVDSCRT11024x768_2; - SiS_Pr->SiS_LVDSCRT11024x768_2_H = SiS300_LVDSCRT11024x768_2_H; - SiS_Pr->SiS_LVDSCRT11280x1024_1 = SiS300_LVDSCRT11280x1024_1; - SiS_Pr->SiS_LVDSCRT11280x1024_1_H = SiS300_LVDSCRT11280x1024_1_H; - SiS_Pr->SiS_LVDSCRT11280x1024_2 = SiS300_LVDSCRT11280x1024_2; - SiS_Pr->SiS_LVDSCRT11280x1024_2_H = SiS300_LVDSCRT11280x1024_2_H; - SiS_Pr->SiS_LVDSCRT1XXXxXXX_1 = SiS300_LVDSCRT1XXXxXXX_1; - SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H = SiS300_LVDSCRT1XXXxXXX_1_H; + SiS_Pr->SiS_LVDS848x480Data_1 = SiS300_LVDS848x480Data_1; + SiS_Pr->SiS_LVDS848x480Data_2 = SiS300_LVDS848x480Data_2; + SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS300_LVDSBARCO1024Data_1; + SiS_Pr->SiS_LVDSBARCO1366Data_1 = SiS300_LVDSBARCO1366Data_1; + SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS300_LVDSBARCO1366Data_2; + + SiS_Pr->SiS_PanelType04_1a = SiS300_PanelType04_1a; + SiS_Pr->SiS_PanelType04_2a = SiS300_PanelType04_2a; + SiS_Pr->SiS_PanelType04_1b = SiS300_PanelType04_1b; + SiS_Pr->SiS_PanelType04_2b = SiS300_PanelType04_2b; SiS_Pr->SiS_CHTVCRT1UNTSC = SiS300_CHTVCRT1UNTSC; SiS_Pr->SiS_CHTVCRT1ONTSC = SiS300_CHTVCRT1ONTSC; @@ -367,64 +239,38 @@ InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) #ifdef SIS315H static void -InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +InitTo310Pointer(struct SiS_Private *SiS_Pr) { - InitCommonPointer(SiS_Pr, HwInfo); + InitCommonPointer(SiS_Pr); - SiS_Pr->SiS_SModeIDTable = SiS310_SModeIDTable; SiS_Pr->SiS_EModeIDTable = SiS310_EModeIDTable; - SiS_Pr->SiS_RefIndex = (SiS_Ext2Struct *)SiS310_RefIndex; + SiS_Pr->SiS_RefIndex = SiS310_RefIndex; SiS_Pr->SiS_CRT1Table = SiS310_CRT1Table; - if(HwInfo->jChipType >= SIS_340) { - SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_340; /* 340 */ - } else if(HwInfo->jChipType >= SIS_761) { + if(SiS_Pr->ChipType >= SIS_340) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_340; /* 340 + XGI */ + } else if(SiS_Pr->ChipType >= SIS_761) { SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_761; /* 761 - preliminary */ - } else if(HwInfo->jChipType >= SIS_760) { + } else if(SiS_Pr->ChipType >= SIS_760) { SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_760; /* 760 */ - } else if(HwInfo->jChipType >= SIS_661) { + } else if(SiS_Pr->ChipType >= SIS_661) { SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_660; /* 661/741 */ - } else if(HwInfo->jChipType == SIS_330) { + } else if(SiS_Pr->ChipType == SIS_330) { SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_330; /* 330 */ - } else if(HwInfo->jChipType > SIS_315PRO) { + } else if(SiS_Pr->ChipType > SIS_315PRO) { SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_650; /* 550, 650, 740 */ } else { SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_315; /* 315 */ } - if(HwInfo->jChipType >= SIS_340) { - SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1_340; + if(SiS_Pr->ChipType >= SIS_340) { + SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1_340; } else { - SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1; + SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1; } SiS_Pr->SiS_VCLKData = SiS310_VCLKData; SiS_Pr->SiS_VBVCLKData = SiS310_VBVCLKData; SiS_Pr->SiS_SR15 = SiS310_SR15; -#ifdef LINUX_KERNEL - SiS_Pr->pSiS_SR07 = &SiS310_SR07; - SiS_Pr->SiS_CR40 = SiS310_CR40; - SiS_Pr->SiS_CR49 = SiS310_CR49; - SiS_Pr->pSiS_SR1F = &SiS310_SR1F; - SiS_Pr->pSiS_SR21 = &SiS310_SR21; - SiS_Pr->pSiS_SR22 = &SiS310_SR22; - SiS_Pr->pSiS_SR23 = &SiS310_SR23; - SiS_Pr->pSiS_SR24 = &SiS310_SR24; - SiS_Pr->SiS_SR25 = SiS310_SR25; - SiS_Pr->pSiS_SR31 = &SiS310_SR31; - SiS_Pr->pSiS_SR32 = &SiS310_SR32; - SiS_Pr->pSiS_SR33 = &SiS310_SR33; - SiS_Pr->pSiS_CRT2Data_1_2 = &SiS310_CRT2Data_1_2; - SiS_Pr->pSiS_CRT2Data_4_D = &SiS310_CRT2Data_4_D; - SiS_Pr->pSiS_CRT2Data_4_E = &SiS310_CRT2Data_4_E; - SiS_Pr->pSiS_CRT2Data_4_10 = &SiS310_CRT2Data_4_10; - SiS_Pr->pSiS_RGBSenseData = &SiS310_RGBSenseData; - SiS_Pr->pSiS_VideoSenseData = &SiS310_VideoSenseData; - SiS_Pr->pSiS_YCSenseData = &SiS310_YCSenseData; - SiS_Pr->pSiS_RGBSenseData2 = &SiS310_RGBSenseData2; - SiS_Pr->pSiS_VideoSenseData2 = &SiS310_VideoSenseData2; - SiS_Pr->pSiS_YCSenseData2 = &SiS310_YCSenseData2; -#endif - SiS_Pr->SiS_PanelDelayTbl = SiS310_PanelDelayTbl; SiS_Pr->SiS_PanelDelayTblLVDS = SiS310_PanelDelayTblLVDS; @@ -435,41 +281,6 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_Pr->SiS_CRT2Part2_1024x768_1 = SiS310_CRT2Part2_1024x768_1; - SiS_Pr->SiS_PanelType00_1 = SiS310_PanelType00_1; - SiS_Pr->SiS_PanelType01_1 = SiS310_PanelType01_1; - SiS_Pr->SiS_PanelType02_1 = SiS310_PanelType02_1; - SiS_Pr->SiS_PanelType03_1 = SiS310_PanelType03_1; - SiS_Pr->SiS_PanelType04_1 = SiS310_PanelType04_1; - SiS_Pr->SiS_PanelType05_1 = SiS310_PanelType05_1; - SiS_Pr->SiS_PanelType06_1 = SiS310_PanelType06_1; - SiS_Pr->SiS_PanelType07_1 = SiS310_PanelType07_1; - SiS_Pr->SiS_PanelType08_1 = SiS310_PanelType08_1; - SiS_Pr->SiS_PanelType09_1 = SiS310_PanelType09_1; - SiS_Pr->SiS_PanelType0a_1 = SiS310_PanelType0a_1; - SiS_Pr->SiS_PanelType0b_1 = SiS310_PanelType0b_1; - SiS_Pr->SiS_PanelType0c_1 = SiS310_PanelType0c_1; - SiS_Pr->SiS_PanelType0d_1 = SiS310_PanelType0d_1; - SiS_Pr->SiS_PanelType0e_1 = SiS310_PanelType0e_1; - SiS_Pr->SiS_PanelType0f_1 = SiS310_PanelType0f_1; - SiS_Pr->SiS_PanelType00_2 = SiS310_PanelType00_2; - SiS_Pr->SiS_PanelType01_2 = SiS310_PanelType01_2; - SiS_Pr->SiS_PanelType02_2 = SiS310_PanelType02_2; - SiS_Pr->SiS_PanelType03_2 = SiS310_PanelType03_2; - SiS_Pr->SiS_PanelType04_2 = SiS310_PanelType04_2; - SiS_Pr->SiS_PanelType05_2 = SiS310_PanelType05_2; - SiS_Pr->SiS_PanelType06_2 = SiS310_PanelType06_2; - SiS_Pr->SiS_PanelType07_2 = SiS310_PanelType07_2; - SiS_Pr->SiS_PanelType08_2 = SiS310_PanelType08_2; - SiS_Pr->SiS_PanelType09_2 = SiS310_PanelType09_2; - SiS_Pr->SiS_PanelType0a_2 = SiS310_PanelType0a_2; - SiS_Pr->SiS_PanelType0b_2 = SiS310_PanelType0b_2; - SiS_Pr->SiS_PanelType0c_2 = SiS310_PanelType0c_2; - SiS_Pr->SiS_PanelType0d_2 = SiS310_PanelType0d_2; - SiS_Pr->SiS_PanelType0e_2 = SiS310_PanelType0e_2; - SiS_Pr->SiS_PanelType0f_2 = SiS310_PanelType0f_2; - SiS_Pr->SiS_PanelTypeNS_1 = SiS310_PanelTypeNS_1; - SiS_Pr->SiS_PanelTypeNS_2 = SiS310_PanelTypeNS_2; - SiS_Pr->SiS_CHTVUPALData = SiS310_CHTVUPALData; SiS_Pr->SiS_CHTVOPALData = SiS310_CHTVOPALData; SiS_Pr->SiS_CHTVUPALMData = SiS310_CHTVUPALMData; @@ -478,33 +289,11 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_Pr->SiS_CHTVOPALNData = SiS310_CHTVOPALNData; SiS_Pr->SiS_CHTVSOPALData = SiS310_CHTVSOPALData; - SiS_Pr->SiS_LVDSCRT1800x600_1 = SiS310_LVDSCRT1800x600_1; - SiS_Pr->SiS_LVDSCRT11024x768_1 = SiS310_LVDSCRT11024x768_1; - SiS_Pr->SiS_LVDSCRT11280x1024_1 = SiS310_LVDSCRT11280x1024_1; - SiS_Pr->SiS_LVDSCRT11400x1050_1 = SiS310_LVDSCRT11400x1050_1; - SiS_Pr->SiS_LVDSCRT11600x1200_1 = SiS310_LVDSCRT11600x1200_1; - SiS_Pr->SiS_LVDSCRT1800x600_1_H = SiS310_LVDSCRT1800x600_1_H; - SiS_Pr->SiS_LVDSCRT11024x768_1_H = SiS310_LVDSCRT11024x768_1_H; - SiS_Pr->SiS_LVDSCRT11280x1024_1_H = SiS310_LVDSCRT11280x1024_1_H; - SiS_Pr->SiS_LVDSCRT11400x1050_1_H = SiS310_LVDSCRT11400x1050_1_H; - SiS_Pr->SiS_LVDSCRT11600x1200_1_H = SiS310_LVDSCRT11600x1200_1_H; - SiS_Pr->SiS_LVDSCRT1800x600_2 = SiS310_LVDSCRT1800x600_2; - SiS_Pr->SiS_LVDSCRT11024x768_2 = SiS310_LVDSCRT11024x768_2; - SiS_Pr->SiS_LVDSCRT11280x1024_2 = SiS310_LVDSCRT11280x1024_2; - SiS_Pr->SiS_LVDSCRT11400x1050_2 = SiS310_LVDSCRT11400x1050_2; - SiS_Pr->SiS_LVDSCRT11600x1200_2 = SiS310_LVDSCRT11600x1200_2; - SiS_Pr->SiS_LVDSCRT1800x600_2_H = SiS310_LVDSCRT1800x600_2_H; - SiS_Pr->SiS_LVDSCRT11024x768_2_H = SiS310_LVDSCRT11024x768_2_H; - SiS_Pr->SiS_LVDSCRT11280x1024_2_H = SiS310_LVDSCRT11280x1024_2_H; - SiS_Pr->SiS_LVDSCRT11400x1050_2_H = SiS310_LVDSCRT11400x1050_2_H; - SiS_Pr->SiS_LVDSCRT11600x1200_2_H = SiS310_LVDSCRT11600x1200_2_H; - SiS_Pr->SiS_LVDSCRT1XXXxXXX_1 = SiS310_LVDSCRT1XXXxXXX_1; - SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H = SiS310_LVDSCRT1XXXxXXX_1_H; - SiS_Pr->SiS_CHTVCRT1UNTSC = SiS310_CHTVCRT1UNTSC; - SiS_Pr->SiS_CHTVCRT1ONTSC = SiS310_CHTVCRT1ONTSC; - SiS_Pr->SiS_CHTVCRT1UPAL = SiS310_CHTVCRT1UPAL; - SiS_Pr->SiS_CHTVCRT1OPAL = SiS310_CHTVCRT1OPAL; - SiS_Pr->SiS_CHTVCRT1SOPAL = SiS310_CHTVCRT1OPAL; + SiS_Pr->SiS_CHTVCRT1UNTSC = SiS310_CHTVCRT1UNTSC; + SiS_Pr->SiS_CHTVCRT1ONTSC = SiS310_CHTVCRT1ONTSC; + SiS_Pr->SiS_CHTVCRT1UPAL = SiS310_CHTVCRT1UPAL; + SiS_Pr->SiS_CHTVCRT1OPAL = SiS310_CHTVCRT1OPAL; + SiS_Pr->SiS_CHTVCRT1SOPAL = SiS310_CHTVCRT1OPAL; SiS_Pr->SiS_CHTVReg_UNTSC = SiS310_CHTVReg_UNTSC; SiS_Pr->SiS_CHTVReg_ONTSC = SiS310_CHTVReg_ONTSC; @@ -528,208 +317,203 @@ InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } #endif -static void -SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +BOOLEAN +SiSInitPtr(struct SiS_Private *SiS_Pr) { - switch(HwInfo->jChipType) { -#ifdef SIS315H - case SIS_315H: - case SIS_315: - case SIS_315PRO: - case SIS_550: - case SIS_650: - case SIS_740: - case SIS_330: - case SIS_661: - case SIS_741: - case SIS_660: - case SIS_760: - case SIS_761: - case SIS_340: - InitTo310Pointer(SiS_Pr, HwInfo); - break; -#endif + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 - case SIS_300: - case SIS_540: - case SIS_630: - case SIS_730: - InitTo300Pointer(SiS_Pr, HwInfo); - break; + InitTo300Pointer(SiS_Pr); +#else + return FALSE; +#endif + } else { +#ifdef SIS315H + InitTo310Pointer(SiS_Pr); +#else + return FALSE; #endif - default: - break; } + return TRUE; } /*********************************************/ /* HELPER: Get ModeID */ /*********************************************/ -#ifdef LINUX_XF86 -USHORT -SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, - int Depth, BOOLEAN FSTN, int LCDwidth, int LCDheight) +#ifndef SIS_XORG_XF86 +static +#endif +unsigned short +SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, + int Depth, BOOLEAN FSTN, int LCDwidth, int LCDheight) { - USHORT ModeIndex = 0; + unsigned short ModeIndex = 0; switch(HDisplay) { - case 320: - if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; - else if(VDisplay == 240) { - if(FSTN) ModeIndex = ModeIndex_320x240_FSTN[Depth]; - else ModeIndex = ModeIndex_320x240[Depth]; - } - break; - case 400: - if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 800) && (LCDwidth >= 600))) { - if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; - } - break; - case 512: - if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 1024) && (LCDwidth >= 768))) { - if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; - } - break; - case 640: - if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; - else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; - break; - case 720: - if(VDisplay == 480) ModeIndex = ModeIndex_720x480[Depth]; - else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth]; - break; - case 768: - if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; - break; - case 800: - if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; - else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth]; - break; - case 848: - if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; - break; - case 856: - if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; - break; - case 960: - if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth]; - else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth]; - } - break; - case 1024: - if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth]; - else if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; - else if(VGAEngine == SIS_300_VGA) { - if(VDisplay == 600) ModeIndex = ModeIndex_1024x600[Depth]; - } - break; - case 1152: - if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth]; - if(VGAEngine == SIS_300_VGA) { - if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth]; - } - break; - case 1280: - switch(VDisplay) { - case 720: - ModeIndex = ModeIndex_1280x720[Depth]; - break; - case 768: - if(VGAEngine == SIS_300_VGA) { - ModeIndex = ModeIndex_300_1280x768[Depth]; - } else { - ModeIndex = ModeIndex_310_1280x768[Depth]; - } - break; - case 800: - if(VGAEngine == SIS_315_VGA) { - ModeIndex = ModeIndex_1280x800[Depth]; - } - break; - case 960: - ModeIndex = ModeIndex_1280x960[Depth]; - break; - case 1024: - ModeIndex = ModeIndex_1280x1024[Depth]; - break; - } - break; - case 1360: - if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; - if(VGAEngine == SIS_300_VGA) { - if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth]; - } - break; - case 1400: - if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 1050) { - ModeIndex = ModeIndex_1400x1050[Depth]; - } - } - break; - case 1600: - if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; - break; - case 1680: - if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; - } - break; - case 1920: - if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth]; - else if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 1080) ModeIndex = ModeIndex_1920x1080[Depth]; - } - break; - case 2048: - if(VDisplay == 1536) { - if(VGAEngine == SIS_300_VGA) { - ModeIndex = ModeIndex_300_2048x1536[Depth]; - } else { - ModeIndex = ModeIndex_310_2048x1536[Depth]; - } - } - break; + case 320: + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + else if(VDisplay == 240) { + if((VBFlags & CRT2_LCD) && (FSTN)) + ModeIndex = ModeIndex_320x240_FSTN[Depth]; + else + ModeIndex = ModeIndex_320x240[Depth]; + } + break; + case 400: + if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 800) && (LCDwidth >= 600))) { + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + } + break; + case 512: + if((!(VBFlags & CRT1_LCDA)) || ((LCDwidth >= 1024) && (LCDwidth >= 768))) { + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + } + break; + case 640: + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; + break; + case 720: + if(VDisplay == 480) ModeIndex = ModeIndex_720x480[Depth]; + else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth]; + break; + case 768: + if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; + break; + case 800: + if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; + else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth]; + break; + case 848: + if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; + break; + case 856: + if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; + break; + case 960: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth]; + else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth]; + } + break; + case 1024: + if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth]; + else if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + else if(VGAEngine == SIS_300_VGA) { + if(VDisplay == 600) ModeIndex = ModeIndex_1024x600[Depth]; + } + break; + case 1152: + if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth]; + if(VGAEngine == SIS_300_VGA) { + if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth]; + } + break; + case 1280: + switch(VDisplay) { + case 720: + ModeIndex = ModeIndex_1280x720[Depth]; + break; + case 768: + if(VGAEngine == SIS_300_VGA) { + ModeIndex = ModeIndex_300_1280x768[Depth]; + } else { + ModeIndex = ModeIndex_310_1280x768[Depth]; + } + break; + case 800: + if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_1280x800[Depth]; + } + break; + case 854: + if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_1280x854[Depth]; + } + break; + case 960: + ModeIndex = ModeIndex_1280x960[Depth]; + break; + case 1024: + ModeIndex = ModeIndex_1280x1024[Depth]; + break; + } + break; + case 1360: + if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; + if(VGAEngine == SIS_300_VGA) { + if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth]; + } + break; + case 1400: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1050) { + ModeIndex = ModeIndex_1400x1050[Depth]; + } + } + break; + case 1600: + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + break; + case 1680: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + } + break; + case 1920: + if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth]; + else if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1080) ModeIndex = ModeIndex_1920x1080[Depth]; + } + break; + case 2048: + if(VDisplay == 1536) { + if(VGAEngine == SIS_300_VGA) { + ModeIndex = ModeIndex_300_2048x1536[Depth]; + } else { + ModeIndex = ModeIndex_310_2048x1536[Depth]; + } + } + break; } - return(ModeIndex); + return ModeIndex; } -#endif -USHORT -SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, - int Depth, BOOLEAN FSTN, USHORT CustomT, int LCDwidth, int LCDheight) +unsigned short +SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, + int Depth, BOOLEAN FSTN, unsigned short CustomT, int LCDwidth, int LCDheight, + unsigned int VBFlags2) { - USHORT ModeIndex = 0; + unsigned short ModeIndex = 0; - if(VBFlags & (VB_LVDS | VB_30xBDH)) { + if(VBFlags2 & (VB2_LVDS | VB2_30xBDH)) { switch(HDisplay) { case 320: - if(CustomT != CUT_PANEL848) { - if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; - else if(VDisplay == 240) { + if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) { + if(VDisplay == 200) { + if(!FSTN) ModeIndex = ModeIndex_320x200[Depth]; + } else if(VDisplay == 240) { if(!FSTN) ModeIndex = ModeIndex_320x240[Depth]; - else if(VGAEngine == SIS_315_VGA) { - ModeIndex = ModeIndex_320x240_FSTN[Depth]; + else if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_320x240_FSTN[Depth]; } } } - break; - case 400: - if(CustomT != CUT_PANEL848) { - if(!((VGAEngine == SIS_300_VGA) && (VBFlags & VB_TRUMPION))) { - if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + break; + case 400: + if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) { + if(!((VGAEngine == SIS_300_VGA) && (VBFlags2 & VB2_TRUMPION))) { + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; } } - break; + break; case 512: - if(CustomT != CUT_PANEL848) { - if(!((VGAEngine == SIS_300_VGA) && (VBFlags & VB_TRUMPION))) { + if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) { + if(!((VGAEngine == SIS_300_VGA) && (VBFlags2 & VB2_TRUMPION))) { if(LCDwidth >= 1024 && LCDwidth != 1152 && LCDheight >= 768) { if(VDisplay == 384) { ModeIndex = ModeIndex_512x384[Depth]; @@ -739,9 +523,10 @@ SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, } break; case 640: - if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; + if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; else if(VDisplay == 400) { - if(CustomT != CUT_PANEL848) ModeIndex = ModeIndex_640x400[Depth]; + if((CustomT != CUT_PANEL848) && (CustomT != CUT_PANEL856)) + ModeIndex = ModeIndex_640x400[Depth]; } break; case 800: @@ -752,6 +537,11 @@ SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; } break; + case 856: + if(CustomT == CUT_PANEL856) { + if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; + } + break; case 1024: if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; else if(VGAEngine == SIS_300_VGA) { @@ -762,7 +552,7 @@ SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, break; case 1152: if(VGAEngine == SIS_300_VGA) { - if((VDisplay == 768) && (LCDheight == 768)) { + if((VDisplay == 768) && (LCDheight == 768)) { ModeIndex = ModeIndex_1152x768[Depth]; } } @@ -770,49 +560,49 @@ SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, case 1280: if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth]; else if(VGAEngine == SIS_315_VGA) { - if((VDisplay == 768) && (LCDheight == 768)) { + if((VDisplay == 768) && (LCDheight == 768)) { ModeIndex = ModeIndex_310_1280x768[Depth]; } } break; case 1360: if(VGAEngine == SIS_300_VGA) { - if(CustomT == CUT_BARCO1366) { + if(CustomT == CUT_BARCO1366) { if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth]; } } if(CustomT == CUT_PANEL848) { - if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; + if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; } break; case 1400: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; + if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; } break; case 1600: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; } break; } - } else if(VBFlags & VB_SISBRIDGE) { + } else if(VBFlags2 & VB2_SISBRIDGE) { switch(HDisplay) { case 320: - if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth]; - break; - case 400: + break; + case 400: if(LCDwidth >= 800 && LCDheight >= 600) { - if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; } - break; + break; case 512: if(LCDwidth >= 1024 && LCDheight >= 768 && LCDwidth != 1152) { - if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; } break; case 640: @@ -821,96 +611,115 @@ SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, break; case 720: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 480) ModeIndex = ModeIndex_720x480[Depth]; + if(VDisplay == 480) ModeIndex = ModeIndex_720x480[Depth]; else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth]; } break; case 768: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; + if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; } break; case 800: if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth]; + if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth]; } break; case 848: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; + if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; } break; case 856: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; + if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; } break; case 960: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth]; + if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth]; else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth]; } break; case 1024: if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth]; + if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth]; } break; case 1152: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth]; + if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth]; } break; case 1280: switch(VDisplay) { case 720: - ModeIndex = ModeIndex_1280x720[Depth]; + ModeIndex = ModeIndex_1280x720[Depth]; case 768: - if(VGAEngine == SIS_300_VGA) { + if(VGAEngine == SIS_300_VGA) { ModeIndex = ModeIndex_300_1280x768[Depth]; } else { ModeIndex = ModeIndex_310_1280x768[Depth]; } break; case 800: - if(VGAEngine == SIS_315_VGA) { + if(VGAEngine == SIS_315_VGA) { ModeIndex = ModeIndex_1280x800[Depth]; } break; + case 854: + if(VGAEngine == SIS_315_VGA) { + ModeIndex = ModeIndex_1280x854[Depth]; + } + break; case 960: - ModeIndex = ModeIndex_1280x960[Depth]; + ModeIndex = ModeIndex_1280x960[Depth]; break; case 1024: - ModeIndex = ModeIndex_1280x1024[Depth]; + ModeIndex = ModeIndex_1280x1024[Depth]; break; } break; case 1360: - if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; + if(VGAEngine == SIS_315_VGA) { /* OVER1280 only? */ + if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; } break; case 1400: if(VGAEngine == SIS_315_VGA) { - if(VBFlags & (VB_301C | VB_302LV | VB_302ELV)) { + if(VBFlags2 & VB2_LCDOVER1280BRIDGE) { if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; } } break; case 1600: if(VGAEngine == SIS_315_VGA) { - if(VBFlags & (VB_301C | VB_302LV | VB_302ELV)) { - if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + if(VBFlags2 & VB2_LCDOVER1280BRIDGE) { + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; } } break; #ifndef VB_FORBID_CRT2LCD_OVER_1600 case 1680: if(VGAEngine == SIS_315_VGA) { - if(VBFlags & (VB_301C | VB_302LV | VB_302ELV)) { - if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + if(VBFlags2 & VB2_LCDOVER1280BRIDGE) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + } + } + break; + case 1920: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags2 & VB2_LCDOVER1600BRIDGE) { + if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth]; + } + } + break; + case 2048: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags2 & VB2_LCDOVER1600BRIDGE) { + if(VDisplay == 1536) ModeIndex = ModeIndex_310_2048x1536[Depth]; } } break; @@ -921,16 +730,17 @@ SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, return ModeIndex; } -USHORT -SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth) +unsigned short +SiS_GetModeID_TV(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, int Depth, + unsigned int VBFlags2) { - USHORT ModeIndex = 0; + unsigned short ModeIndex = 0; - if(VBFlags & VB_CHRONTEL) { + if(VBFlags2 & VB2_CHRONTEL) { switch(HDisplay) { - case 512: + case 512: if(VGAEngine == SIS_315_VGA) { if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; } @@ -944,27 +754,27 @@ SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int D break; case 1024: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; + if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; } break; } - } else if(VBFlags & VB_SISTVBRIDGE) { + } else if(VBFlags2 & VB2_SISTVBRIDGE) { switch(HDisplay) { case 320: - if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; + if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth]; - break; - case 400: - if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; - break; - case 512: + break; + case 400: + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + break; + case 512: if( ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR750P | TV_YPBPR1080I))) || - (VBFlags & TV_HIVISION) || - ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) { - if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; + (VBFlags & TV_HIVISION) || + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) { + if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; } break; case 640: @@ -973,34 +783,34 @@ SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int D break; case 720: if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) { - if(VDisplay == 480) { - ModeIndex = ModeIndex_720x480[Depth]; - } else if(VDisplay == 576) { + if(VDisplay == 480) { + ModeIndex = ModeIndex_720x480[Depth]; + } else if(VDisplay == 576) { if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) || ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) - ModeIndex = ModeIndex_720x576[Depth]; - } + ModeIndex = ModeIndex_720x576[Depth]; + } } break; case 768: if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) { - if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) || + if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) || ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) { - if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; + if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; } } break; case 800: if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; else if(VDisplay == 480) { - if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { + if(!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P))) { ModeIndex = ModeIndex_800x480[Depth]; } } break; case 960: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 600) { + if(VDisplay == 600) { if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { ModeIndex = ModeIndex_960x600[Depth]; } @@ -1009,25 +819,28 @@ SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int D break; case 1024: if(VDisplay == 768) { - if(VBFlags & (VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV|VB_302ELV)) { + if(VBFlags2 & VB2_30xBLV) { ModeIndex = ModeIndex_1024x768[Depth]; } } else if(VDisplay == 576) { - if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { + if( (VBFlags & TV_HIVISION) || + ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)) || + ((VBFlags2 & VB2_30xBLV) && + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL))) ) { ModeIndex = ModeIndex_1024x576[Depth]; } } break; case 1280: if(VDisplay == 720) { - if((VBFlags & TV_HIVISION) || + if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)))) { - ModeIndex = ModeIndex_1280x720[Depth]; + ModeIndex = ModeIndex_1280x720[Depth]; } } else if(VDisplay == 1024) { - if((VBFlags & TV_HIVISION) || + if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { - ModeIndex = ModeIndex_1280x1024[Depth]; + ModeIndex = ModeIndex_1280x1024[Depth]; } } break; @@ -1036,99 +849,31 @@ SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int D return ModeIndex; } -USHORT -SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth) +unsigned short +SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, int Depth, + unsigned int VBFlags2) { - USHORT ModeIndex = 0; + if(!(VBFlags2 & VB2_SISVGA2BRIDGE)) return 0; - if(!(VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0; + if(HDisplay >= 1920) return 0; switch(HDisplay) { - case 320: - if(VDisplay == 200) ModeIndex = ModeIndex_320x200[Depth]; - else if(VDisplay == 240) ModeIndex = ModeIndex_320x240[Depth]; - break; - case 400: - if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; - break; - case 512: - if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; - break; - case 640: - if(VDisplay == 480) ModeIndex = ModeIndex_640x480[Depth]; - else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; - break; - case 720: - if(VDisplay == 480) ModeIndex = ModeIndex_720x480[Depth]; - else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth]; - break; - case 768: - if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; - break; - case 800: - if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; - else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth]; - break; - case 848: - if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth]; - break; - case 856: - if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth]; - break; - case 960: - if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth]; - else if(VDisplay == 600) ModeIndex = ModeIndex_960x600[Depth]; - } - break; - case 1024: - if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth]; - else if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth]; - break; - case 1152: - if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth]; - else if(VGAEngine == SIS_300_VGA) { - if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth]; - } - break; - case 1280: - if(VDisplay == 768) { - if(VGAEngine == SIS_300_VGA) { - ModeIndex = ModeIndex_300_1280x768[Depth]; - } else { - ModeIndex = ModeIndex_310_1280x768[Depth]; - } - } else if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth]; - else if(VDisplay == 720) ModeIndex = ModeIndex_1280x720[Depth]; - else if(VDisplay == 800) ModeIndex = ModeIndex_1280x800[Depth]; - else if(VDisplay == 960) ModeIndex = ModeIndex_1280x960[Depth]; - break; - case 1360: - if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth]; - break; - case 1400: - if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; - } - break; case 1600: - if(VGAEngine == SIS_315_VGA) { - if(VBFlags & (VB_301B|VB_301C|VB_302B)) { - if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; - } + if(VDisplay == 1200) { + if(VGAEngine != SIS_315_VGA) return 0; + if(!(VBFlags2 & VB2_30xB)) return 0; } break; case 1680: - if(VGAEngine == SIS_315_VGA) { - if(VBFlags & (VB_301B|VB_301C|VB_302B)) { - if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; - } + if(VDisplay == 1050) { + if(VGAEngine != SIS_315_VGA) return 0; + if(!(VBFlags2 & VB2_30xB)) return 0; } break; } - return ModeIndex; + return SiS_GetModeID(VGAEngine, 0, HDisplay, VDisplay, Depth, FALSE, 0, 0); } @@ -1137,83 +882,83 @@ SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int /*********************************************/ void -SiS_SetReg(SISIOADDRESS port, USHORT index, USHORT data) +SiS_SetReg(SISIOADDRESS port, unsigned short index, unsigned short data) { - OutPortByte(port,index); - OutPortByte(port + 1,data); + OutPortByte(port, index); + OutPortByte(port + 1, data); } void -SiS_SetRegByte(SISIOADDRESS port, USHORT data) +SiS_SetRegByte(SISIOADDRESS port, unsigned short data) { - OutPortByte(port,data); + OutPortByte(port, data); } void -SiS_SetRegShort(SISIOADDRESS port, USHORT data) +SiS_SetRegShort(SISIOADDRESS port, unsigned short data) { - OutPortWord(port,data); + OutPortWord(port, data); } void -SiS_SetRegLong(SISIOADDRESS port, ULONG data) +SiS_SetRegLong(SISIOADDRESS port, unsigned int data) { - OutPortLong(port,data); + OutPortLong(port, data); } -UCHAR -SiS_GetReg(SISIOADDRESS port, USHORT index) +unsigned char +SiS_GetReg(SISIOADDRESS port, unsigned short index) { - OutPortByte(port,index); + OutPortByte(port, index); return(InPortByte(port + 1)); } -UCHAR +unsigned char SiS_GetRegByte(SISIOADDRESS port) { return(InPortByte(port)); } -USHORT +unsigned short SiS_GetRegShort(SISIOADDRESS port) { return(InPortWord(port)); } -ULONG +unsigned int SiS_GetRegLong(SISIOADDRESS port) { return(InPortLong(port)); } void -SiS_SetRegANDOR(SISIOADDRESS Port,USHORT Index,USHORT DataAND,USHORT DataOR) +SiS_SetRegANDOR(SISIOADDRESS Port, unsigned short Index, unsigned short DataAND, unsigned short DataOR) { - USHORT temp; + unsigned short temp; - temp = SiS_GetReg(Port,Index); - temp = (temp & (DataAND)) | DataOR; - SiS_SetReg(Port,Index,temp); + temp = SiS_GetReg(Port, Index); + temp = (temp & (DataAND)) | DataOR; + SiS_SetReg(Port, Index, temp); } void -SiS_SetRegAND(SISIOADDRESS Port,USHORT Index,USHORT DataAND) +SiS_SetRegAND(SISIOADDRESS Port, unsigned short Index, unsigned short DataAND) { - USHORT temp; + unsigned short temp; - temp = SiS_GetReg(Port,Index); - temp &= DataAND; - SiS_SetReg(Port,Index,temp); + temp = SiS_GetReg(Port, Index); + temp &= DataAND; + SiS_SetReg(Port, Index, temp); } void -SiS_SetRegOR(SISIOADDRESS Port,USHORT Index,USHORT DataOR) +SiS_SetRegOR(SISIOADDRESS Port, unsigned short Index, unsigned short DataOR) { - USHORT temp; + unsigned short temp; - temp = SiS_GetReg(Port,Index); - temp |= DataOR; - SiS_SetReg(Port,Index,temp); + temp = SiS_GetReg(Port, Index); + temp |= DataOR; + SiS_SetReg(Port, Index, temp); } /*********************************************/ @@ -1221,13 +966,13 @@ SiS_SetRegOR(SISIOADDRESS Port,USHORT Index,USHORT DataOR) /*********************************************/ void -SiS_DisplayOn(SiS_Private *SiS_Pr) +SiS_DisplayOn(struct SiS_Private *SiS_Pr) { SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x01,0xDF); } void -SiS_DisplayOff(SiS_Private *SiS_Pr) +SiS_DisplayOff(struct SiS_Private *SiS_Pr) { SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20); } @@ -1238,7 +983,7 @@ SiS_DisplayOff(SiS_Private *SiS_Pr) /*********************************************/ void -SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr) +SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr) { SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; @@ -1251,16 +996,17 @@ SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr) SiS_Pr->SiS_P3c8 = BaseAddr + 0x18; SiS_Pr->SiS_P3c9 = BaseAddr + 0x19; SiS_Pr->SiS_P3cb = BaseAddr + 0x1b; + SiS_Pr->SiS_P3cc = BaseAddr + 0x1c; SiS_Pr->SiS_P3cd = BaseAddr + 0x1d; SiS_Pr->SiS_P3da = BaseAddr + 0x2a; - SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; /* Digital video interface registers (LCD) */ - SiS_Pr->SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10; /* 301 TV Encoder registers */ - SiS_Pr->SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12; /* 301 Macrovision registers */ - SiS_Pr->SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14; /* 301 VGA2 (and LCD) registers */ - SiS_Pr->SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2; /* 301 palette address port registers */ - SiS_Pr->SiS_DDC_Port = BaseAddr + 0x14; /* DDC Port ( = P3C4, SR11/0A) */ - SiS_Pr->SiS_VidCapt = BaseAddr + SIS_VIDEO_CAPTURE; - SiS_Pr->SiS_VidPlay = BaseAddr + SIS_VIDEO_PLAYBACK; + SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; + SiS_Pr->SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10; + SiS_Pr->SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12; + SiS_Pr->SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14; + SiS_Pr->SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2; + SiS_Pr->SiS_DDC_Port = BaseAddr + 0x14; + SiS_Pr->SiS_VidCapt = BaseAddr + SIS_VIDEO_CAPTURE; + SiS_Pr->SiS_VidPlay = BaseAddr + SIS_VIDEO_PLAYBACK; } /*********************************************/ @@ -1268,7 +1014,7 @@ SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr) /*********************************************/ static void -SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_GetSysFlags(struct SiS_Private *SiS_Pr) { unsigned char cr5f, temp1, temp2; @@ -1276,9 +1022,9 @@ SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /* (SR11 is used for DDC and in enable/disablebridge) */ SiS_Pr->SiS_SensibleSR11 = FALSE; SiS_Pr->SiS_MyCR63 = 0x63; - if(HwInfo->jChipType >= SIS_330) { + if(SiS_Pr->ChipType >= SIS_330) { SiS_Pr->SiS_MyCR63 = 0x53; - if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->ChipType >= SIS_661) { SiS_Pr->SiS_SensibleSR11 = TRUE; } } @@ -1286,43 +1032,52 @@ SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /* You should use the macros, not these flags directly */ SiS_Pr->SiS_SysFlags = 0; - if(HwInfo->jChipType == SIS_650) { + if(SiS_Pr->ChipType == SIS_650) { cr5f = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0; SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x5c,0x07); temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8; SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x5c,0xf8); temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8; if((!temp1) || (temp2)) { - switch(cr5f) { + switch(cr5f) { case 0x80: case 0x90: case 0xc0: - SiS_Pr->SiS_SysFlags |= SF_IsM650; break; + SiS_Pr->SiS_SysFlags |= SF_IsM650; + break; case 0xa0: case 0xb0: case 0xe0: - SiS_Pr->SiS_SysFlags |= SF_Is651; break; + SiS_Pr->SiS_SysFlags |= SF_Is651; + break; } } else { - switch(cr5f) { + switch(cr5f) { case 0x90: temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8; switch(temp1) { - case 0x00: SiS_Pr->SiS_SysFlags |= SF_IsM652; break; + case 0x00: SiS_Pr->SiS_SysFlags |= SF_IsM652; break; case 0x40: SiS_Pr->SiS_SysFlags |= SF_IsM653; break; default: SiS_Pr->SiS_SysFlags |= SF_IsM650; break; } break; case 0xb0: - SiS_Pr->SiS_SysFlags |= SF_Is652; break; + SiS_Pr->SiS_SysFlags |= SF_Is652; + break; default: - SiS_Pr->SiS_SysFlags |= SF_IsM650; break; + SiS_Pr->SiS_SysFlags |= SF_IsM650; + break; } } } - if(HwInfo->jChipType == SIS_760) { - temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78); - if(temp1 & 0x30) SiS_Pr->SiS_SysFlags |= SF_760LFB; + + if(SiS_Pr->ChipType >= SIS_760 && SiS_Pr->ChipType <= SIS_761) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x30) { + SiS_Pr->SiS_SysFlags |= SF_760LFB; + } + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0xf0) { + SiS_Pr->SiS_SysFlags |= SF_760UMA; + } } } @@ -1331,18 +1086,20 @@ SiS_GetSysFlags(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /*********************************************/ static void -SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiSInitPCIetc(struct SiS_Private *SiS_Pr) { - switch(HwInfo->jChipType) { + switch(SiS_Pr->ChipType) { +#ifdef SIS300 case SIS_300: case SIS_540: case SIS_630: case SIS_730: /* Set - PCI LINEAR ADDRESSING ENABLE (0x80) - * - RELOCATED VGA IO (0x20) - * - MMIO ENABLE (0x1) + * - RELOCATED VGA IO ENABLED (0x20) + * - MMIO ENABLED (0x01) + * Leave other bits untouched. */ - SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x20,0xa1); /* - Enable 2D (0x40) * - Enable 3D (0x02) * - Enable 3D Vertex command fetch (0x10) ? @@ -1350,6 +1107,8 @@ SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) */ SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x5A); break; +#endif +#ifdef SIS315H case SIS_315H: case SIS_315: case SIS_315PRO: @@ -1362,21 +1121,30 @@ SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) case SIS_760: case SIS_761: case SIS_340: - SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1); - /* - Enable 2D (0x40) - * - Enable 3D (0x02) + case XGI_40: + /* See above */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x20,0xa1); + /* - Enable 3D G/L transformation engine (0x80) + * - Enable 2D (0x40) * - Enable 3D vertex command fetch (0x10) * - Enable 3D command parser (0x08) - * - Enable 3D G/L transformation engine (0x80) + * - Enable 3D (0x02) */ SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0xDA); break; + case XGI_20: case SIS_550: - SiS_SetReg(SiS_Pr->SiS_P3c4,0x20,0xa1); + /* See above */ + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x20,0xa1); /* No 3D engine ! */ /* - Enable 2D (0x40) + * - disable 3D */ - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x40); + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1E,0x60,0x40); + break; +#endif + default: + break; } } @@ -1384,38 +1152,40 @@ SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /* HELPER: SetLVDSetc */ /*********************************************/ -static void -SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +#ifdef SIS_LINUX_KERNEL +static +#endif +void +SiSSetLVDSetc(struct SiS_Private *SiS_Pr) { - USHORT temp; + unsigned short temp; SiS_Pr->SiS_IF_DEF_LVDS = 0; SiS_Pr->SiS_IF_DEF_TRUMPION = 0; SiS_Pr->SiS_IF_DEF_CH70xx = 0; - SiS_Pr->SiS_IF_DEF_DSTN = 0; - SiS_Pr->SiS_IF_DEF_FSTN = 0; SiS_Pr->SiS_IF_DEF_CONEX = 0; SiS_Pr->SiS_ChrontelInit = 0; + if(SiS_Pr->ChipType == XGI_20) return; + /* Check for SiS30x first */ temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); if((temp == 1) || (temp == 2)) return; - switch(HwInfo->jChipType) { + switch(SiS_Pr->ChipType) { #ifdef SIS300 case SIS_540: case SIS_630: case SIS_730: - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); - temp = (temp & 0x0E) >> 1; - if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1; - if(temp == 3) SiS_Pr->SiS_IF_DEF_TRUMPION = 1; - if((temp == 4) || (temp == 5)) { + temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x37) & 0x0e) >> 1; + if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_TRUMPION = 1; + if((temp == 4) || (temp == 5)) { /* Save power status (and error check) - UNUSED */ SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr, 0x0e); SiS_Pr->SiS_IF_DEF_CH70xx = 1; - } + } break; #endif #ifdef SIS315H @@ -1423,26 +1193,26 @@ SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) case SIS_650: case SIS_740: case SIS_330: - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); - temp = (temp & 0x0E) >> 1; - if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; - if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; - break; + temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x37) & 0x0e) >> 1; + if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; + break; case SIS_661: case SIS_741: case SIS_660: case SIS_760: case SIS_761: case SIS_340: - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - temp = (temp & 0xe0) >> 5; - if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; - if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; - if(temp == 4) SiS_Pr->SiS_IF_DEF_CONEX = 1; /* Not yet supported */ - break; + case XGI_20: + case XGI_40: + temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & 0xe0) >> 5; + if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; + if(temp == 4) SiS_Pr->SiS_IF_DEF_CONEX = 1; /* Not yet supported */ + break; #endif default: - break; + break; } } @@ -1451,35 +1221,55 @@ SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /*********************************************/ void -SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable) +SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable) { SiS_Pr->SiS_IF_DEF_DSTN = enable ? 1 : 0; } void -SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable) +SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable) { SiS_Pr->SiS_IF_DEF_FSTN = enable ? 1 : 0; } +/*********************************************/ +/* HELPER: Get modeflag */ +/*********************************************/ + +unsigned short +SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) +{ + if(SiS_Pr->UseCustomMode) { + return SiS_Pr->CModeFlag; + } else if(ModeNo <= 0x13) { + return SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + return SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } +} + /*********************************************/ /* HELPER: Determine ROM usage */ /*********************************************/ BOOLEAN -SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT romversoffs, romvmaj = 1, romvmin = 0; - - if(HwInfo->jChipType >= SIS_761) { - /* I very much assume 761 and 340 will use new layout */ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romversoffs, romvmaj = 1, romvmin = 0; + + if(SiS_Pr->ChipType >= XGI_20) { + /* XGI ROMs don't qualify */ + return FALSE; + } else if(SiS_Pr->ChipType >= SIS_761) { + /* I very much assume 761, 340 and newer will use new layout */ return TRUE; - } else if(HwInfo->jChipType >= SIS_661) { + } else if(SiS_Pr->ChipType >= SIS_661) { if((ROMAddr[0x1a] == 'N') && - (ROMAddr[0x1b] == 'e') && - (ROMAddr[0x1c] == 'w') && - (ROMAddr[0x1d] == 'V')) { + (ROMAddr[0x1b] == 'e') && + (ROMAddr[0x1c] == 'w') && + (ROMAddr[0x1d] == 'V')) { return TRUE; } romversoffs = ROMAddr[0x16] | (ROMAddr[0x17] << 8); @@ -1494,9 +1284,9 @@ SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } } else if(IS_SIS650740) { if((ROMAddr[0x1a] == 'N') && - (ROMAddr[0x1b] == 'e') && - (ROMAddr[0x1c] == 'w') && - (ROMAddr[0x1d] == 'V')) { + (ROMAddr[0x1b] == 'e') && + (ROMAddr[0x1c] == 'w') && + (ROMAddr[0x1d] == 'V')) { return TRUE; } } @@ -1504,45 +1294,50 @@ SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } static void -SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiSDetermineROMUsage(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT romptr = 0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr = 0; SiS_Pr->SiS_UseROM = FALSE; SiS_Pr->SiS_ROMNew = FALSE; + SiS_Pr->SiS_PWDOffset = 0; - if((ROMAddr) && (HwInfo->UseROM)) { - if(HwInfo->jChipType == SIS_300) { - /* 300: We check if the code starts below 0x220 by + if(SiS_Pr->ChipType >= XGI_20) return; + + if((ROMAddr) && (SiS_Pr->UseROM)) { + if(SiS_Pr->ChipType == SIS_300) { + /* 300: We check if the code starts below 0x220 by * checking the jmp instruction at the beginning * of the BIOS image. */ if((ROMAddr[3] == 0xe9) && ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a) SiS_Pr->SiS_UseROM = TRUE; - } else if(HwInfo->jChipType < SIS_315H) { + } else if(SiS_Pr->ChipType < SIS_315H) { /* Sony's VAIO BIOS 1.09 follows the standard, so perhaps * the others do as well */ SiS_Pr->SiS_UseROM = TRUE; } else { - /* 315/330 series stick to the standard(s) */ + /* 315/330 series stick to the standard(s) */ SiS_Pr->SiS_UseROM = TRUE; - if((SiS_Pr->SiS_ROMNew = SiSDetermineROMLayout661(SiS_Pr, HwInfo))) { + if((SiS_Pr->SiS_ROMNew = SiSDetermineROMLayout661(SiS_Pr))) { SiS_Pr->SiS_EMIOffset = 14; + SiS_Pr->SiS_PWDOffset = 17; SiS_Pr->SiS661LCD2TableSize = 36; /* Find out about LCD data table entry size */ if((romptr = SISGETROMW(0x0102))) { if(ROMAddr[romptr + (32 * 16)] == 0xff) - SiS_Pr->SiS661LCD2TableSize = 32; + SiS_Pr->SiS661LCD2TableSize = 32; else if(ROMAddr[romptr + (34 * 16)] == 0xff) - SiS_Pr->SiS661LCD2TableSize = 34; - else if(ROMAddr[romptr + (36 * 16)] == 0xff) /* 0.94 */ - SiS_Pr->SiS661LCD2TableSize = 36; + SiS_Pr->SiS661LCD2TableSize = 34; + else if(ROMAddr[romptr + (36 * 16)] == 0xff) /* 0.94, 2.05.00+ */ + SiS_Pr->SiS661LCD2TableSize = 36; else if( (ROMAddr[romptr + (38 * 16)] == 0xff) || /* 2.00.00 - 2.02.00 */ - (ROMAddr[0x6F] & 0x01) ) { /* 2.03.00+ */ - SiS_Pr->SiS661LCD2TableSize = 38; + (ROMAddr[0x6F] & 0x01) ) { /* 2.03.00 - <2.05.00 */ + SiS_Pr->SiS661LCD2TableSize = 38; /* UMC data layout abandoned at 2.05.00 */ SiS_Pr->SiS_EMIOffset = 16; + SiS_Pr->SiS_PWDOffset = 19; } } } @@ -1555,9 +1350,9 @@ SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /*********************************************/ static void -SiS_SetSegRegLower(SiS_Private *SiS_Pr, USHORT value) +SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) { - USHORT temp; + unsigned short temp; value &= 0x00ff; temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0xf0; @@ -1569,9 +1364,9 @@ SiS_SetSegRegLower(SiS_Private *SiS_Pr, USHORT value) } static void -SiS_SetSegRegUpper(SiS_Private *SiS_Pr, USHORT value) +SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) { - USHORT temp; + unsigned short temp; value &= 0x00ff; temp = SiS_GetRegByte(SiS_Pr->SiS_P3cb) & 0x0f; @@ -1583,22 +1378,22 @@ SiS_SetSegRegUpper(SiS_Private *SiS_Pr, USHORT value) } static void -SiS_SetSegmentReg(SiS_Private *SiS_Pr, USHORT value) +SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) { SiS_SetSegRegLower(SiS_Pr, value); SiS_SetSegRegUpper(SiS_Pr, value); } static void -SiS_ResetSegmentReg(SiS_Private *SiS_Pr) +SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) { SiS_SetSegmentReg(SiS_Pr, 0); } static void -SiS_SetSegmentRegOver(SiS_Private *SiS_Pr, USHORT value) +SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value) { - USHORT temp = value >> 8; + unsigned short temp = value >> 8; temp &= 0x07; temp |= (temp << 4); @@ -1607,15 +1402,15 @@ SiS_SetSegmentRegOver(SiS_Private *SiS_Pr, USHORT value) } static void -SiS_ResetSegmentRegOver(SiS_Private *SiS_Pr) +SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) { SiS_SetSegmentRegOver(SiS_Pr, 0); } static void -SiS_ResetSegmentRegisters(SiS_Private *SiS_Pr,PSIS_HW_INFO HwInfo) +SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) { - if((IS_SIS65x) || (HwInfo->jChipType >= SIS_661)) { + if((IS_SIS65x) || (SiS_Pr->ChipType >= SIS_661)) { SiS_ResetSegmentReg(SiS_Pr); SiS_ResetSegmentRegOver(SiS_Pr); } @@ -1625,154 +1420,153 @@ SiS_ResetSegmentRegisters(SiS_Private *SiS_Pr,PSIS_HW_INFO HwInfo) /* HELPER: GetVBType */ /*********************************************/ -static void -SiS_GetVBType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +#ifdef SIS_LINUX_KERNEL +static +#endif +void +SiS_GetVBType(struct SiS_Private *SiS_Pr) { - USHORT flag=0, rev=0, nolcd=0, p4_0f, p4_25, p4_27; - - SiS_Pr->SiS_VBType = 0; - - if((SiS_Pr->SiS_IF_DEF_LVDS) || (SiS_Pr->SiS_IF_DEF_CONEX)) - return; - - flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); - - if(flag > 3) return; - - rev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); - - if(flag >= 2) { - SiS_Pr->SiS_VBType = VB_SIS302B; - } else if(flag == 1) { - if(rev >= 0xC0) { - SiS_Pr->SiS_VBType = VB_SIS301C; - } else if(rev >= 0xB0) { - SiS_Pr->SiS_VBType = VB_SIS301B; - /* Check if 30xB DH version (no LCD support, use Panel Link instead) */ - nolcd = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x23); - if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD; - } else { - SiS_Pr->SiS_VBType = VB_SIS301; - } - } - if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) { - if(rev >= 0xE0) { - flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39); - if(flag == 0xff) SiS_Pr->SiS_VBType = VB_SIS302LV; - else SiS_Pr->SiS_VBType = VB_SIS301C; /* VB_SIS302ELV; */ - } else if(rev >= 0xD0) { - SiS_Pr->SiS_VBType = VB_SIS301LV; - } - } - if(SiS_Pr->SiS_VBType & (VB_301C | VB_301LV | VB_302LV | VB_302ELV)) { - p4_0f = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0f); - p4_25 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x25); - p4_27 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x27); - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0x7f); - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x25,0x08); - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,0xfd); - if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x08) { - SiS_Pr->SiS_VBType |= VB_UMC; - } - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x27,p4_27); - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x25,p4_25); - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0f,p4_0f); - } -} + unsigned short flag = 0, rev = 0, nolcd = 0; + unsigned short p4_0f, p4_25, p4_27; -/*********************************************/ -/* HELPER: Check RAM size */ -/*********************************************/ + SiS_Pr->SiS_VBType = 0; -#ifdef LINUX_KERNEL -static BOOLEAN -SiS_CheckMemorySize(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo, USHORT ModeIdIndex) -{ - USHORT AdapterMemSize = HwInfo->ulVideoMemorySize / (1024*1024); - USHORT memorysize,modeflag; - - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - } else { - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } - } - - memorysize = modeflag & MemoryInfoFlag; - memorysize >>= MemorySizeShift; /* Get required memory size */ - memorysize++; - - if(AdapterMemSize < memorysize) return FALSE; - return TRUE; -} -#endif + if((SiS_Pr->SiS_IF_DEF_LVDS) || (SiS_Pr->SiS_IF_DEF_CONEX)) + return; + + if(SiS_Pr->ChipType == XGI_20) + return; + + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); + + if(flag > 3) + return; + + rev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); + + if(flag >= 2) { + SiS_Pr->SiS_VBType = VB_SIS302B; + } else if(flag == 1) { + if(rev >= 0xC0) { + SiS_Pr->SiS_VBType = VB_SIS301C; + } else if(rev >= 0xB0) { + SiS_Pr->SiS_VBType = VB_SIS301B; + /* Check if 30xB DH version (no LCD support, use Panel Link instead) */ + nolcd = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x23); + if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD; + } else { + SiS_Pr->SiS_VBType = VB_SIS301; + } + } + if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) { + if(rev >= 0xE0) { + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39); + if(flag == 0xff) SiS_Pr->SiS_VBType = VB_SIS302LV; + else SiS_Pr->SiS_VBType = VB_SIS301C; /* VB_SIS302ELV; */ + } else if(rev >= 0xD0) { + SiS_Pr->SiS_VBType = VB_SIS301LV; + } + } + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) { + p4_0f = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x0f); + p4_25 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x25); + p4_27 = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x27); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0x7f); + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x25,0x08); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,0xfd); + if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x08) { + SiS_Pr->SiS_VBType |= VB_UMC; + } + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x27,p4_27); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x25,p4_25); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0f,p4_0f); + } +} + +/*********************************************/ +/* HELPER: Check RAM size */ +/*********************************************/ + +#ifdef SIS_LINUX_KERNEL +static BOOLEAN +SiS_CheckMemorySize(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) +{ + unsigned short AdapterMemSize = SiS_Pr->VideoMemorySize / (1024*1024); + unsigned short modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + unsigned short memorysize = ((modeflag & MemoryInfoFlag) >> MemorySizeShift) + 1; + + if(!AdapterMemSize) return TRUE; + + if(AdapterMemSize < memorysize) return FALSE; + return TRUE; +} +#endif /*********************************************/ /* HELPER: Get DRAM type */ /*********************************************/ #ifdef SIS315H -static UCHAR -SiS_Get310DRAMType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +static unsigned char +SiS_Get310DRAMType(struct SiS_Private *SiS_Pr) { - UCHAR data, temp; + unsigned char data; if((*SiS_Pr->pSiS_SoftSetting) & SoftDRAMType) { - data = (*SiS_Pr->pSiS_SoftSetting) & 0x03; + data = (*SiS_Pr->pSiS_SoftSetting) & 0x03; } else { - if(HwInfo->jChipType >= SIS_340) { - /* TODO */ - data = 0; - } if(HwInfo->jChipType >= SIS_661) { - data = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x07; - if(SiS_Pr->SiS_ROMNew) { - data = ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0xc0) >> 6); - } - } else if(IS_SIS550650740) { - data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x07; - } else { /* 315, 330 */ - data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3a) & 0x03; - if(HwInfo->jChipType == SIS_330) { - if(data > 1) { - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0x30; - switch(temp) { - case 0x00: data = 1; break; - case 0x10: data = 3; break; - case 0x20: data = 3; break; - case 0x30: data = 2; break; - } - } else { - data = 0; - } - } - } + if(SiS_Pr->ChipType >= XGI_20) { + /* Do I need this? SR17 seems to be zero anyway... */ + data = 0; + } else if(SiS_Pr->ChipType >= SIS_340) { + /* TODO */ + data = 0; + } if(SiS_Pr->ChipType >= SIS_661) { + if(SiS_Pr->SiS_ROMNew) { + data = ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0xc0) >> 6); + } else { + data = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x07; + } + } else if(IS_SIS550650740) { + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x07; + } else { /* 315, 330 */ + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3a) & 0x03; + if(SiS_Pr->ChipType == SIS_330) { + if(data > 1) { + switch(SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0x30) { + case 0x00: data = 1; break; + case 0x10: data = 3; break; + case 0x20: data = 3; break; + case 0x30: data = 2; break; + } + } else { + data = 0; + } + } + } } return data; } -static USHORT -SiS_GetMCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +static unsigned short +SiS_GetMCLK(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index; - - index = SiS_Get310DRAMType(SiS_Pr, HwInfo); - if(HwInfo->jChipType >= SIS_661) { - if(SiS_Pr->SiS_ROMNew) { - return((USHORT)(SISGETROMW((0x90 + (index * 5) + 3)))); - } - return(SiS_Pr->SiS_MCLKData_0[index].CLOCK); - } else if(index >= 4) { - index -= 4; - return(SiS_Pr->SiS_MCLKData_1[index].CLOCK); - } else { - return(SiS_Pr->SiS_MCLKData_0[index].CLOCK); - } + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index; + + index = SiS_Get310DRAMType(SiS_Pr); + if(SiS_Pr->ChipType >= SIS_661) { + if(SiS_Pr->SiS_ROMNew) { + return((unsigned short)(SISGETROMW((0x90 + (index * 5) + 3)))); + } + return(SiS_Pr->SiS_MCLKData_0[index].CLOCK); + } else if(index >= 4) { + return(SiS_Pr->SiS_MCLKData_1[index - 4].CLOCK); + } else { + return(SiS_Pr->SiS_MCLKData_0[index].CLOCK); + } } #endif @@ -1780,30 +1574,30 @@ SiS_GetMCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /* HELPER: ClearBuffer */ /*********************************************/ -#ifdef LINUX_KERNEL +#ifdef SIS_LINUX_KERNEL static void -SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) +SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { - UCHAR SISIOMEMTYPE *VideoMemoryAddress = HwInfo->pjVideoMemoryAddress; - ULONG AdapterMemorySize = HwInfo->ulVideoMemorySize; - USHORT SISIOMEMTYPE *pBuffer; - int i; - - if(SiS_Pr->SiS_ModeType >= ModeEGA) { - if(ModeNo > 0x13) { - SiS_SetMemory(VideoMemoryAddress, AdapterMemorySize, 0); - } else { - pBuffer = (USHORT SISIOMEMTYPE *)VideoMemoryAddress; - for(i=0; i<0x4000; i++) writew(0x0000, &pBuffer[i]); - } - } else { - if(SiS_Pr->SiS_ModeType < ModeCGA) { - pBuffer = (USHORT SISIOMEMTYPE *)VideoMemoryAddress; - for(i=0; i<0x4000; i++) writew(0x0720, &pBuffer[i]); - } else { - SiS_SetMemory(VideoMemoryAddress, 0x8000, 0); - } - } + unsigned char SISIOMEMTYPE *memaddr = SiS_Pr->VideoMemoryAddress; + unsigned int memsize = SiS_Pr->VideoMemorySize; + unsigned short SISIOMEMTYPE *pBuffer; + int i; + + if(!memaddr || !memsize) return; + + if(SiS_Pr->SiS_ModeType >= ModeEGA) { + if(ModeNo > 0x13) { + SiS_SetMemory(memaddr, memsize, 0); + } else { + pBuffer = (unsigned short SISIOMEMTYPE *)memaddr; + for(i = 0; i < 0x4000; i++) writew(0x0000, &pBuffer[i]); + } + } else if(SiS_Pr->SiS_ModeType < ModeCGA) { + pBuffer = (unsigned short SISIOMEMTYPE *)memaddr; + for(i = 0; i < 0x4000; i++) writew(0x0720, &pBuffer[i]); + } else { + SiS_SetMemory(memaddr, 0x8000, 0); + } } #endif @@ -1812,35 +1606,36 @@ SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) /*********************************************/ BOOLEAN -SiS_SearchModeID(SiS_Private *SiS_Pr, USHORT *ModeNo, USHORT *ModeIdIndex) +SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, + unsigned short *ModeIdIndex) { - UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO; + unsigned char VGAINFO = SiS_Pr->SiS_VGAINFO; - if(*ModeNo <= 0x13) { + if((*ModeNo) <= 0x13) { if((*ModeNo) <= 0x05) (*ModeNo) |= 0x01; - for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { - if(SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == (*ModeNo)) break; - if(SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == 0xFF) return FALSE; + for((*ModeIdIndex) = 0; ;(*ModeIdIndex)++) { + if(SiS_Pr->SiS_SModeIDTable[(*ModeIdIndex)].St_ModeID == (*ModeNo)) break; + if(SiS_Pr->SiS_SModeIDTable[(*ModeIdIndex)].St_ModeID == 0xFF) return FALSE; } - if(*ModeNo == 0x07) { - if(VGAINFO & 0x10) (*ModeIdIndex)++; /* 400 lines */ - /* else 350 lines */ + if((*ModeNo) == 0x07) { + if(VGAINFO & 0x10) (*ModeIdIndex)++; /* 400 lines */ + /* else 350 lines */ } - if(*ModeNo <= 0x03) { - if(!(VGAINFO & 0x80)) (*ModeIdIndex)++; - if(VGAINFO & 0x10) (*ModeIdIndex)++; /* 400 lines */ - /* else 350 lines */ + if((*ModeNo) <= 0x03) { + if(!(VGAINFO & 0x80)) (*ModeIdIndex)++; + if(VGAINFO & 0x10) (*ModeIdIndex)++; /* 400 lines */ + /* else 350 lines */ } /* else 200 lines */ } else { - for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) { - if(SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) break; - if(SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) return FALSE; + for((*ModeIdIndex) = 0; ;(*ModeIdIndex)++) { + if(SiS_Pr->SiS_EModeIDTable[(*ModeIdIndex)].Ext_ModeID == (*ModeNo)) break; + if(SiS_Pr->SiS_EModeIDTable[(*ModeIdIndex)].Ext_ModeID == 0xFF) return FALSE; } } @@ -1851,10 +1646,10 @@ SiS_SearchModeID(SiS_Private *SiS_Pr, USHORT *ModeNo, USHORT *ModeIdIndex) /* HELPER: GetModePtr */ /*********************************************/ -UCHAR -SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex) +unsigned short +SiS_GetModePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - UCHAR index; + unsigned short index; if(ModeNo <= 0x13) { index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex; @@ -1865,80 +1660,126 @@ SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex) return index; } +/*********************************************/ +/* HELPERS: Get some indices */ +/*********************************************/ + +unsigned short +SiS_GetRefCRTVCLK(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide) +{ + if(SiS_Pr->SiS_RefIndex[Index].Ext_InfoFlag & HaveWideTiming) { + if(UseWide == 1) { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRTVCLK_WIDE; + } else { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRTVCLK_NORM; + } + } else { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRTVCLK; + } +} + +unsigned short +SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide) +{ + if(SiS_Pr->SiS_RefIndex[Index].Ext_InfoFlag & HaveWideTiming) { + if(UseWide == 1) { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRT1CRTC_WIDE; + } else { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRT1CRTC_NORM; + } + } else { + return SiS_Pr->SiS_RefIndex[Index].Ext_CRT1CRTC; + } +} + /*********************************************/ /* HELPER: LowModeTests */ /*********************************************/ static BOOLEAN -SiS_DoLowModeTest(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo) +SiS_DoLowModeTest(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { - USHORT temp,temp1,temp2; - - if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12)) - return(TRUE); - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x11); - SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80); - temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,0x55); - temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,temp1); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x11,temp); - if((HwInfo->jChipType >= SIS_315H) || - (HwInfo->jChipType == SIS_300)) { - if(temp2 == 0x55) return(FALSE); - else return(TRUE); - } else { - if(temp2 != 0x55) return(TRUE); - else { - SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); - return(FALSE); - } - } + unsigned short temp, temp1, temp2; + + if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12)) + return TRUE; + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x11); + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80); + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,0x55); + temp2 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,temp1); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x11,temp); + if((SiS_Pr->ChipType >= SIS_315H) || + (SiS_Pr->ChipType == SIS_300)) { + if(temp2 == 0x55) return FALSE; + else return TRUE; + } else { + if(temp2 != 0x55) return TRUE; + else { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); + return FALSE; + } + } } static void -SiS_SetLowModeTest(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo) +SiS_SetLowModeTest(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { - if(SiS_DoLowModeTest(SiS_Pr, ModeNo, HwInfo)) { - SiS_Pr->SiS_SetFlag |= LowModeTests; - } + if(SiS_DoLowModeTest(SiS_Pr, ModeNo)) { + SiS_Pr->SiS_SetFlag |= LowModeTests; + } } /*********************************************/ -/* HELPER: ENABLE CRT1 */ +/* HELPER: OPEN/CLOSE CRT1 CRTC */ /*********************************************/ static void -SiS_SetupCR5x(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_OpenCRTC(struct SiS_Private *SiS_Pr) +{ + if(IS_SIS650) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); + if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); + } else if(IS_SIS661741660760) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x61,0xf7); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); + if(!SiS_Pr->SiS_ROMNew) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef); + } + } +} + +static void +SiS_CloseCRTC(struct SiS_Private *SiS_Pr) { - if(IS_SIS650) { - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); - if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20); - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); - } - } else if(IS_SIS661741660760) { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x61,0xf7); - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); - if(!SiS_Pr->SiS_ROMNew) { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef); - } - } +#if 0 /* This locks some CRTC registers. We don't want that. */ + unsigned short temp1 = 0, temp2 = 0; + + if(IS_SIS661741660760) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + temp1 = 0xa0; temp2 = 0x08; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x51,0x1f,temp1); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x56,0xe7,temp2); + } +#endif } static void -SiS_HandleCRT1(SiS_Private *SiS_Pr) +SiS_HandleCRT1(struct SiS_Private *SiS_Pr) { - /* Enable CRT1 gating */ - SiS_SetRegAND(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0xbf); + /* Enable CRT1 gating */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0xbf); #if 0 - if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) { - if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) || - (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) { - SiS_SetRegOR(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0x40); - } - } + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) { + if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) || + (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0x40); + } + } #endif } @@ -1946,57 +1787,54 @@ SiS_HandleCRT1(SiS_Private *SiS_Pr) /* HELPER: GetColorDepth */ /*********************************************/ -USHORT -SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex) +unsigned short +SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) { - USHORT ColorDepth[6] = { 1, 2, 4, 4, 6, 8}; - SHORT index; - USHORT modeflag; - - /* Do NOT check UseCustomMode, will skrew up FIFO */ - if(ModeNo == 0xfe) { - modeflag = SiS_Pr->CModeFlag; - } else { - if(ModeNo <= 0x13) - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - else - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } - - index = (modeflag & ModeTypeMask) - ModeEGA; - if(index < 0) index = 0; - return(ColorDepth[index]); + static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 }; + unsigned short modeflag; + short index; + + /* Do NOT check UseCustomMode, will skrew up FIFO */ + if(ModeNo == 0xfe) { + modeflag = SiS_Pr->CModeFlag; + } else if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + index = (modeflag & ModeTypeMask) - ModeEGA; + if(index < 0) index = 0; + return ColorDepth[index]; } /*********************************************/ /* HELPER: GetOffset */ /*********************************************/ -USHORT -SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, - USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo) +unsigned short +SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) { - USHORT xres, temp, colordepth, infoflag; - - if(SiS_Pr->UseCustomMode) { - infoflag = SiS_Pr->CInfoFlag; - xres = SiS_Pr->CHDisplay; - } else { - infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; - xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes; - } - - colordepth = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex); - - temp = xres / 16; - if(infoflag & InterlaceMode) temp <<= 1; - temp *= colordepth; - if(xres % 16) { - colordepth >>= 1; - temp += colordepth; - } - - return(temp); + unsigned short xres, temp, colordepth, infoflag; + + if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + xres = SiS_Pr->CHDisplay; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag; + xres = SiS_Pr->SiS_RefIndex[RRTI].XRes; + } + + colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex); + + temp = xres / 16; + if(infoflag & InterlaceMode) temp <<= 1; + temp *= colordepth; + if(xres % 16) temp += (colordepth >> 1); + + return temp; } /*********************************************/ @@ -2004,55 +1842,29 @@ SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, /*********************************************/ static void -SiS_SetSeqRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, PSIS_HW_INFO HwInfo) +SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) { - UCHAR SRdata; - USHORT i; + unsigned char SRdata; + int i; - SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x03); /* Set SR0 */ + SiS_SetReg(SiS_Pr->SiS_P3c4,0x00,0x03); - SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0]; + /* or "display off" */ + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - SRdata |= 0x01; - } - if(HwInfo->jChipType >= SIS_661) { - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - SRdata |= 0x01; /* 8 dot clock */ - } - } - } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_VBType & VB_NoLCD) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - SRdata |= 0x01; /* 8 dot clock */ - } - } - } - } + /* determine whether to force x8 dotclock */ + if((SiS_Pr->SiS_VBType & VB_SISVB) || (SiS_Pr->SiS_IF_DEF_LVDS)) { - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - SRdata |= 0x01; /* 8 dot clock */ - } - } - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - SRdata |= 0x01; /* 8 dot clock */ - } - } - } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) SRdata |= 0x01; + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) SRdata |= 0x01; - SRdata |= 0x20; /* screen off */ + } SiS_SetReg(SiS_Pr->SiS_P3c4,0x01,SRdata); for(i = 2; i <= 4; i++) { - SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1]; + SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1]; SiS_SetReg(SiS_Pr->SiS_P3c4,i,SRdata); } } @@ -2062,17 +1874,17 @@ SiS_SetSeqRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, PSIS_HW_INFO HwInfo) /*********************************************/ static void -SiS_SetMiscRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, PSIS_HW_INFO HwInfo) +SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) { - UCHAR Miscdata; + unsigned char Miscdata; Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC; - if(HwInfo->jChipType < SIS_661) { - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - Miscdata |= 0x0C; - } + if(SiS_Pr->ChipType < SIS_661) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + Miscdata |= 0x0C; + } } } @@ -2084,33 +1896,34 @@ SiS_SetMiscRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, PSIS_HW_INFO HwInfo /*********************************************/ static void -SiS_SetCRTCRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT StandTableIndex) +SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) { - UCHAR CRTCdata; - USHORT i; - - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); /* Unlock CRTC */ - - for(i = 0; i <= 0x18; i++) { - CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; - SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata); /* Set CRTC(3d4) */ - } - if(HwInfo->jChipType >= SIS_661) { - SiS_SetupCR5x(SiS_Pr, HwInfo); - for(i = 0x13; i <= 0x14; i++) { - CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; - SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata); - } - } else if( ( (HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730) ) && - (HwInfo->jChipRevision >= 0x30) ) { /* for 630S0 */ - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { - SiS_SetReg(SiS_Pr->SiS_P3d4,0x18,0xFE); - } - } - } + unsigned char CRTCdata; + unsigned short i; + + /* Unlock CRTC */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); + + for(i = 0; i <= 0x18; i++) { + CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata); + } + + if(SiS_Pr->ChipType >= SIS_661) { + SiS_OpenCRTC(SiS_Pr); + for(i = 0x13; i <= 0x14; i++) { + CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata); + } + } else if( ( (SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730) ) && + (SiS_Pr->ChipRevision >= 0x30) ) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x18,0xFE); + } + } + } } /*********************************************/ @@ -2118,64 +1931,58 @@ SiS_SetCRTCRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, /*********************************************/ static void -SiS_SetATTRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, - PSIS_HW_INFO HwInfo) +SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) { - UCHAR ARdata; - USHORT i; + unsigned char ARdata; + unsigned short i; for(i = 0; i <= 0x13; i++) { ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; -#if 0 - if((i <= 0x0f) || (i == 0x11)) { - if(ds:489 & 0x08) { - continue; - } - } -#endif + if(i == 0x13) { - /* Pixel shift. If screen on LCD or TV is shifted left or right, - * this might be the cause. - */ - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ARdata=0; - } - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0; - } - } - } - if(HwInfo->jChipType >= SIS_661) { + /* Pixel shift. If screen on LCD or TV is shifted left or right, + * this might be the cause. + */ + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ARdata = 0; + } + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0; + } + } + } + if(SiS_Pr->ChipType >= SIS_661) { if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0; } } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { if(IS_SIS550650740660) { - /* 315, 330 don't do this */ - if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0; - } else { - ARdata = 0; - } + /* 315, 330 don't do this */ + if(SiS_Pr->SiS_VBType & VB_SIS30xB) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0; + } else { + ARdata = 0; + } } } else { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata = 0; } - } + } } - SiS_GetRegByte(SiS_Pr->SiS_P3da); /* reset 3da */ - SiS_SetRegByte(SiS_Pr->SiS_P3c0,i); /* set index */ - SiS_SetRegByte(SiS_Pr->SiS_P3c0,ARdata); /* set data */ + SiS_GetRegByte(SiS_Pr->SiS_P3da); /* reset 3da */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,i); /* set index */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,ARdata); /* set data */ } - SiS_GetRegByte(SiS_Pr->SiS_P3da); /* reset 3da */ - SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x14); /* set index */ - SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x00); /* set data */ + + SiS_GetRegByte(SiS_Pr->SiS_P3da); /* reset 3da */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x14); /* set index */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x00); /* set data */ SiS_GetRegByte(SiS_Pr->SiS_P3da); - SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x20); /* Enable Attribute */ + SiS_SetRegByte(SiS_Pr->SiS_P3c0,0x20); /* Enable Attribute */ SiS_GetRegByte(SiS_Pr->SiS_P3da); } @@ -2184,10 +1991,10 @@ SiS_SetATTRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex, /*********************************************/ static void -SiS_SetGRCRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex) +SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) { - UCHAR GRdata; - USHORT i; + unsigned char GRdata; + unsigned short i; for(i = 0; i <= 0x08; i++) { GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; @@ -2205,22 +2012,22 @@ SiS_SetGRCRegs(SiS_Private *SiS_Pr, USHORT StandTableIndex) /*********************************************/ static void -SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) +SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { - USHORT i; + unsigned short i; - for(i = 0x0A; i <= 0x0E; i++) { - SiS_SetReg(SiS_Pr->SiS_P3c4,i,0x00); - } + for(i = 0x0A; i <= 0x0E; i++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,i,0x00); + } - if(HwInfo->jChipType >= SIS_315H) { - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE); - if(ModeNo <= 0x13) { - if(ModeNo == 0x06 || ModeNo >= 0x0e) { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e,0x20); - } - } - } + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE); + if(ModeNo <= 0x13) { + if(ModeNo == 0x06 || ModeNo >= 0x0e) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e,0x20); + } + } + } } /*********************************************/ @@ -2228,32 +2035,24 @@ SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) /*********************************************/ static void -SiS_ResetCRT1VCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_ResetCRT1VCLK(struct SiS_Private *SiS_Pr) { - if(HwInfo->jChipType >= SIS_315H) { - if(HwInfo->jChipType < SIS_661) { - if(SiS_Pr->SiS_IF_DEF_LVDS == 0) return; + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->ChipType < SIS_661) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 0) return; } } else { if((SiS_Pr->SiS_IF_DEF_LVDS == 0) && - (!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) { + (!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) ) { return; } } - if(HwInfo->jChipType >= SIS_315H) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xCF,0x20); - } else { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x20); - } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x20); SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[1].SR2B); SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[1].SR2C); SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80); - if(HwInfo->jChipType >= SIS_315H) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x10); - } else { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x10); - } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x10); SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[0].SR2B); SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[0].SR2C); SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80); @@ -2264,19 +2063,19 @@ SiS_ResetCRT1VCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /*********************************************/ static void -SiS_SetCRT1Sync(SiS_Private *SiS_Pr, USHORT RefreshRateTableIndex) +SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short RRTI) { - USHORT sync; + unsigned short sync; - if(SiS_Pr->UseCustomMode) { - sync = SiS_Pr->CInfoFlag >> 8; - } else { - sync = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8; - } + if(SiS_Pr->UseCustomMode) { + sync = SiS_Pr->CInfoFlag >> 8; + } else { + sync = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag >> 8; + } - sync &= 0xC0; - sync |= 0x2f; - SiS_SetRegByte(SiS_Pr->SiS_P3c2,sync); + sync &= 0xC0; + sync |= 0x2f; + SiS_SetRegByte(SiS_Pr->SiS_P3c2,sync); } /*********************************************/ @@ -2284,72 +2083,67 @@ SiS_SetCRT1Sync(SiS_Private *SiS_Pr, USHORT RefreshRateTableIndex) /*********************************************/ static void -SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, - PSIS_HW_INFO HwInfo) +SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) { - UCHAR index; - USHORT temp,i,j,modeflag; - - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); /* unlock cr0-7 */ - - if(SiS_Pr->UseCustomMode) { - - modeflag = SiS_Pr->CModeFlag; - - for(i=0,j=0;i<=7;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); - } - for(j=0x10;i<=10;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); - } - for(j=0x15;i<=12;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); - } - for(j=0x0A;i<=15;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]); - } - - temp = SiS_Pr->CCRT1CRTC[16] & 0xE0; - SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp); - - temp = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5; - if(modeflag & DoubleScanMode) temp |= 0x80; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp); - - } else { - - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } - - index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - - for(i=0,j=0;i<=7;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - for(j=0x10;i<=10;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - for(j=0x15;i<=12;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - for(j=0x0A;i<=15;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - - temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; - SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp); - - temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; - if(modeflag & DoubleScanMode) temp |= 0x80; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp); - - } - - if(SiS_Pr->SiS_ModeType > ModeVGA) SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F); + unsigned short temp, i, j, modeflag; + unsigned char *crt1data = NULL; + + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + if(SiS_Pr->UseCustomMode) { + + crt1data = &SiS_Pr->CCRT1CRTC[0]; + + } else { + + temp = SiS_GetRefCRT1CRTC(SiS_Pr, RRTI, SiS_Pr->SiS_UseWide); + + /* Alternate for 1600x1200 LCDA */ + if((temp == 0x20) && (SiS_Pr->Alternate1600x1200)) temp = 0x57; + + crt1data = (unsigned char *)&SiS_Pr->SiS_CRT1Table[temp].CR[0]; + + } + + /* unlock cr0-7 */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); + + for(i = 0, j = 0; i <= 7; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,crt1data[i]); + } + for(j = 0x10; i <= 10; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,crt1data[i]); + } + for(j = 0x15; i <= 12; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,crt1data[i]); + } + for(j = 0x0A; i <= 15; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,j,crt1data[i]); + } + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,crt1data[16] & 0xE0); + + temp = (crt1data[16] & 0x01) << 5; + if(modeflag & DoubleScanMode) temp |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp); + + if(SiS_Pr->SiS_ModeType > ModeVGA) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F); + } + +#ifdef SIS315H + if(SiS_Pr->ChipType == XGI_20) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x04,crt1data[4] - 1); + if(!(temp = crt1data[5] & 0x1f)) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0c,0xfb); + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x05,0xe0,((temp - 1) & 0x1f)); + temp = (crt1data[16] >> 5) + 3; + if(temp > 7) temp -= 7; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0e,0x1f,(temp << 5)); + } +#endif } /*********************************************/ @@ -2359,33 +2153,32 @@ SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ static void -SiS_SetCRT1Offset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, - PSIS_HW_INFO HwInfo) +SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) { - USHORT temp, DisplayUnit, infoflag; + unsigned short temp, DisplayUnit, infoflag; if(SiS_Pr->UseCustomMode) { infoflag = SiS_Pr->CInfoFlag; } else { - infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + infoflag = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag; } - DisplayUnit = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex, - RefreshRateTableIndex,HwInfo); + DisplayUnit = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, RRTI); temp = (DisplayUnit >> 8) & 0x0f; SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,temp); - temp = DisplayUnit & 0xFF; - SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,temp); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,DisplayUnit & 0xFF); if(infoflag & InterlaceMode) DisplayUnit >>= 1; DisplayUnit <<= 5; - temp = (DisplayUnit & 0xff00) >> 8; + temp = (DisplayUnit >> 8) + 1; if(DisplayUnit & 0xff) temp++; - temp++; + if(SiS_Pr->ChipType == XGI_20) { + if(ModeNo == 0x4a || ModeNo == 0x49) temp--; + } SiS_SetReg(SiS_Pr->SiS_P3c4,0x10,temp); } @@ -2394,39 +2187,49 @@ SiS_SetCRT1Offset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ static void -SiS_SetCRT1VCLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex) +SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) { - USHORT index=0, clka, clkb; - - if(SiS_Pr->UseCustomMode) { - clka = SiS_Pr->CSR2B; - clkb = SiS_Pr->CSR2C; - } else { - index = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { - clka = SiS_Pr->SiS_VBVCLKData[index].Part4_A; - clkb = SiS_Pr->SiS_VBVCLKData[index].Part4_B; - } else { - clka = SiS_Pr->SiS_VCLKData[index].SR2B; - clkb = SiS_Pr->SiS_VCLKData[index].SR2C; - } - } - - if(HwInfo->jChipType >= SIS_315H) { - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF); - } else { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x00); - } - - SiS_SetReg(SiS_Pr->SiS_P3c4,0x2B,clka); - SiS_SetReg(SiS_Pr->SiS_P3c4,0x2C,clkb); - - if(HwInfo->jChipType >= SIS_315H) { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x01); - } else { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80); - } + unsigned short index = 0, clka, clkb; + + if(SiS_Pr->UseCustomMode) { + clka = SiS_Pr->CSR2B; + clkb = SiS_Pr->CSR2C; + } else { + index = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RRTI); + if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && + (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + /* Alternate for 1600x1200 LCDA */ + if((index == 0x21) && (SiS_Pr->Alternate1600x1200)) index = 0x72; + clka = SiS_Pr->SiS_VBVCLKData[index].Part4_A; + clkb = SiS_Pr->SiS_VBVCLKData[index].Part4_B; + } else { + clka = SiS_Pr->SiS_VCLKData[index].SR2B; + clkb = SiS_Pr->SiS_VCLKData[index].SR2C; + } + } + + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF); + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2b,clka); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,clkb); + + if(SiS_Pr->ChipType >= SIS_315H) { +#ifdef SIS315H + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x01); + if(SiS_Pr->ChipType == XGI_20) { + unsigned short mf = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + if(mf & HalfDCLK) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2b,SiS_GetReg(SiS_Pr->SiS_P3c4,0x2b)); + clkb = SiS_GetReg(SiS_Pr->SiS_P3c4,0x2c); + clkb = (((clkb & 0x1f) << 1) + 1) | (clkb & 0xe0); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,clkb); + } + } +#endif + } else { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2D,0x80); + } } /*********************************************/ @@ -2434,802 +2237,730 @@ SiS_SetCRT1VCLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ #ifdef SIS300 -static USHORT -SiS_DoCalcDelay(SiS_Private *SiS_Pr, USHORT MCLK, USHORT VCLK, USHORT colordepth, USHORT key) +void +SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1, + unsigned short *idx2) { - const UCHAR ThLowA[] = { 61, 3,52, 5,68, 7,100,11, - 43, 3,42, 5,54, 7, 78,11, - 34, 3,37, 5,47, 7, 67,11 }; - - const UCHAR ThLowB[] = { 81, 4,72, 6,88, 8,120,12, - 55, 4,54, 6,66, 8, 90,12, - 42, 4,45, 6,55, 8, 75,12 }; - - const UCHAR ThTiming[] = { 1, 2, 2, 3, 0, 1, 1, 2 }; - - USHORT tempah, tempal, tempcl, tempbx, temp; - ULONG longtemp; - - tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18); - tempah &= 0x62; - tempah >>= 1; - tempal = tempah; - tempah >>= 3; - tempal |= tempah; - tempal &= 0x07; - tempcl = ThTiming[tempal]; - tempbx = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16); - tempbx >>= 6; - tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); - tempah >>= 4; - tempah &= 0x0c; - tempbx |= tempah; - tempbx <<= 1; - if(key == 0) { - tempal = ThLowA[tempbx + 1]; - tempal *= tempcl; - tempal += ThLowA[tempbx]; - } else { - tempal = ThLowB[tempbx + 1]; - tempal *= tempcl; - tempal += ThLowB[tempbx]; - } - longtemp = tempal * VCLK * colordepth; - temp = longtemp % (MCLK * 16); - longtemp /= (MCLK * 16); - if(temp) longtemp++; - return((USHORT)longtemp); + unsigned short temp1, temp2; + static const unsigned char ThTiming[8] = { + 1, 2, 2, 3, 0, 1, 1, 2 + }; + + temp1 = temp2 = (SiS_GetReg(SiS_Pr->SiS_P3c4,0x18) & 0x62) >> 1; + (*idx2) = (unsigned short)(ThTiming[((temp2 >> 3) | temp1) & 0x07]); + (*idx1) = (unsigned short)(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) >> 6) & 0x03; + (*idx1) |= (unsigned short)(((SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) >> 4) & 0x0c)); + (*idx1) <<= 1; } -static USHORT -SiS_CalcDelay(SiS_Private *SiS_Pr, USHORT VCLK, USHORT colordepth, USHORT MCLK) +static unsigned short +SiS_GetFIFOThresholdA300(unsigned short idx1, unsigned short idx2) { - USHORT tempax, tempbx; - - tempbx = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 0); - tempax = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 1); - if(tempax < 4) tempax = 4; - tempax -= 4; - if(tempbx < tempax) tempbx = tempax; - return(tempbx); -} + static const unsigned char ThLowA[8 * 3] = { + 61, 3,52, 5,68, 7,100,11, + 43, 3,42, 5,54, 7, 78,11, + 34, 3,37, 5,47, 7, 67,11 + }; -static void -SiS_SetCRT1FIFO_300(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo, - USHORT RefreshRateTableIndex) -{ - USHORT ThresholdLow = 0; - USHORT index, VCLK, MCLK, colorth=0; - USHORT tempah, temp; - - if(ModeNo > 0x13) { - - if(SiS_Pr->UseCustomMode) { - VCLK = SiS_Pr->CSRClock; - } else { - index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; - index &= 0x3F; - VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ - } - - switch (SiS_Pr->SiS_ModeType - ModeEGA) { /* Get half colordepth */ - case 0 : colorth = 1; break; - case 1 : colorth = 1; break; - case 2 : colorth = 2; break; - case 3 : colorth = 2; break; - case 4 : colorth = 3; break; - case 5 : colorth = 4; break; - } - - index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A); - index &= 0x07; - MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK; /* Get MCLK */ - - tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); - tempah &= 0xc3; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3c,tempah); - - do { - ThresholdLow = SiS_CalcDelay(SiS_Pr, VCLK, colorth, MCLK); - ThresholdLow++; - if(ThresholdLow < 0x13) break; - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x16,0xfc); - ThresholdLow = 0x13; - tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16); - tempah >>= 6; - if(!(tempah)) break; - tempah--; - tempah <<= 6; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3f,tempah); - } while(0); - - } else ThresholdLow = 2; - - /* Write CRT/CPU threshold low, CRT/Engine threshold high */ - temp = (ThresholdLow << 4) | 0x0f; - SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,temp); - - temp = (ThresholdLow & 0x10) << 1; - if(ModeNo > 0x13) temp |= 0x40; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0f,0x9f,temp); - - /* What is this? */ - SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09); - - /* Write CRT/CPU threshold high */ - temp = ThresholdLow + 3; - if(temp > 0x0f) temp = 0x0f; - SiS_SetReg(SiS_Pr->SiS_P3c4,0x09,temp); + return (unsigned short)((ThLowA[idx1 + 1] * idx2) + ThLowA[idx1]); } -static USHORT -SiS_CalcDelay2(SiS_Private *SiS_Pr, UCHAR key, PSIS_HW_INFO HwInfo) +unsigned short +SiS_GetFIFOThresholdB300(unsigned short idx1, unsigned short idx2) { - USHORT data,index; - const UCHAR LatencyFactor[] = { - 97, 88, 86, 79, 77, 00, /*; 64 bit BQ=2 */ - 00, 87, 85, 78, 76, 54, /*; 64 bit BQ=1 */ - 97, 88, 86, 79, 77, 00, /*; 128 bit BQ=2 */ - 00, 79, 77, 70, 68, 48, /*; 128 bit BQ=1 */ - 80, 72, 69, 63, 61, 00, /*; 64 bit BQ=2 */ - 00, 70, 68, 61, 59, 37, /*; 64 bit BQ=1 */ - 86, 77, 75, 68, 66, 00, /*; 128 bit BQ=2 */ - 00, 68, 66, 59, 57, 37 /*; 128 bit BQ=1 */ - }; - const UCHAR LatencyFactor730[] = { - 69, 63, 61, - 86, 79, 77, - 103, 96, 94, - 120,113,111, - 137,130,128, /* --- Table ends with this entry, data below */ - 137,130,128, /* to avoid using illegal values */ - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - }; - - if(HwInfo->jChipType == SIS_730) { - index = ((key & 0x0f) * 3) + ((key & 0xC0) >> 6); - data = LatencyFactor730[index]; - } else { - index = (key & 0xE0) >> 5; - if(key & 0x10) index +=6; - if(!(key & 0x01)) index += 24; - data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); - if(data & 0x0080) index += 12; - data = LatencyFactor[index]; - } - return(data); + static const unsigned char ThLowB[8 * 3] = { + 81, 4,72, 6,88, 8,120,12, + 55, 4,54, 6,66, 8, 90,12, + 42, 4,45, 6,55, 8, 75,12 + }; + + return (unsigned short)((ThLowB[idx1 + 1] * idx2) + ThLowB[idx1]); } -static void -SiS_SetCRT1FIFO_630(SiS_Private *SiS_Pr, USHORT ModeNo, - PSIS_HW_INFO HwInfo, - USHORT RefreshRateTableIndex) +static unsigned short +SiS_DoCalcDelay(struct SiS_Private *SiS_Pr, unsigned short MCLK, unsigned short VCLK, + unsigned short colordepth, unsigned short key) { - USHORT i,index,data,VCLK,MCLK,colorth=0; - ULONG B,eax,bl,data2; - USHORT ThresholdLow=0; - UCHAR FQBQData[]= { - 0x01,0x21,0x41,0x61,0x81, - 0x31,0x51,0x71,0x91,0xb1, - 0x00,0x20,0x40,0x60,0x80, - 0x30,0x50,0x70,0x90,0xb0, - 0xFF - }; - UCHAR FQBQData730[]= { - 0x34,0x74,0xb4, - 0x23,0x63,0xa3, - 0x12,0x52,0x92, - 0x01,0x41,0x81, - 0x00,0x40,0x80, - 0xff - }; - - i=0; - if(ModeNo > 0x13) { - if(SiS_Pr->UseCustomMode) { - VCLK = SiS_Pr->CSRClock; - } else { - index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; - index &= 0x3F; - VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ - } - - index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A); - index &= 0x07; - MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK; /* Get MCLK */ - - data2 = SiS_Pr->SiS_ModeType - ModeEGA; /* Get half colordepth */ - switch (data2) { - case 0 : colorth = 1; break; - case 1 : colorth = 1; break; - case 2 : colorth = 2; break; - case 3 : colorth = 2; break; - case 4 : colorth = 3; break; - case 5 : colorth = 4; break; - } - - if(HwInfo->jChipType == SIS_730) { - - do { - B = SiS_CalcDelay2(SiS_Pr, FQBQData730[i], HwInfo) * VCLK * colorth; - bl = B / (MCLK * 16); - - if(B == bl * 16 * MCLK) { - bl = bl + 1; - } else { - bl = bl + 2; - } - - if(bl > 0x13) { - if(FQBQData730[i+1] == 0xFF) { - ThresholdLow = 0x13; - break; - } - i++; - } else { - ThresholdLow = bl; - break; - } - } while(FQBQData730[i] != 0xFF); + unsigned short idx1, idx2; + unsigned int longtemp = VCLK * colordepth; - } else { + SiS_GetFIFOThresholdIndex300(SiS_Pr, &idx1, &idx2); - do { - B = SiS_CalcDelay2(SiS_Pr, FQBQData[i], HwInfo) * VCLK * colorth; - bl = B / (MCLK * 16); + if(key == 0) { + longtemp *= SiS_GetFIFOThresholdA300(idx1, idx2); + } else { + longtemp *= SiS_GetFIFOThresholdB300(idx1, idx2); + } + idx1 = longtemp % (MCLK * 16); + longtemp /= (MCLK * 16); + if(idx1) longtemp++; + return (unsigned short)longtemp; +} - if(B == bl * 16 * MCLK) { - bl = bl + 1; - } else { - bl = bl + 2; - } +static unsigned short +SiS_CalcDelay(struct SiS_Private *SiS_Pr, unsigned short VCLK, + unsigned short colordepth, unsigned short MCLK) +{ + unsigned short temp1, temp2; + + temp2 = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 0); + temp1 = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 1); + if(temp1 < 4) temp1 = 4; + temp1 -= 4; + if(temp2 < temp1) temp2 = temp1; + return temp2; +} - if(bl > 0x13) { - if(FQBQData[i+1] == 0xFF) { - ThresholdLow = 0x13; - break; - } - i++; - } else { - ThresholdLow = bl; - break; - } - } while(FQBQData[i] != 0xFF); - } - } - else { - if(HwInfo->jChipType == SIS_730) { - } else { - i = 9; - } - ThresholdLow = 0x02; - } +static void +SiS_SetCRT1FIFO_300(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short RefreshRateTableIndex) +{ + unsigned short ThresholdLow = 0; + unsigned short temp, index, VCLK, MCLK, colorth; + static const unsigned short colortharray[6] = { 1, 1, 2, 2, 3, 4 }; - /* Write foreground and background queue */ - if(HwInfo->jChipType == SIS_730) { - - data2 = FQBQData730[i]; - data2 = (data2 & 0xC0) >> 5; - data2 <<= 8; - -#ifdef LINUX_KERNEL - SiS_SetRegLong(0xcf8,0x80000050); - eax = SiS_GetRegLong(0xcfc); - eax &= 0xfffff9ff; - eax |= data2; - SiS_SetRegLong(0xcfc,eax); -#else - /* We use pci functions X offers. We use pcitag 0, because - * we want to read/write to the host bridge (which is always - * 00:00.0 on 630, 730 and 540), not the VGA device. - */ - eax = pciReadLong(0x00000000, 0x50); - eax &= 0xfffff9ff; - eax |= data2; - pciWriteLong(0x00000000, 0x50, eax); -#endif + if(ModeNo > 0x13) { - /* Write GUI grant timer (PCI config 0xA3) */ - data2 = FQBQData730[i] << 8; - data2 = (data2 & 0x0f00) | ((data2 & 0x3000) >> 8); - data2 <<= 20; - -#ifdef LINUX_KERNEL - SiS_SetRegLong(0xcf8,0x800000A0); - eax = SiS_GetRegLong(0xcfc); - eax &= 0x00ffffff; - eax |= data2; - SiS_SetRegLong(0xcfc,eax); -#else - eax = pciReadLong(0x00000000, 0xA0); - eax &= 0x00ffffff; - eax |= data2; - pciWriteLong(0x00000000, 0xA0, eax); -#endif + /* Get VCLK */ + if(SiS_Pr->UseCustomMode) { + VCLK = SiS_Pr->CSRClock; + } else { + index = SiS_GetRefCRTVCLK(SiS_Pr, RefreshRateTableIndex, SiS_Pr->SiS_UseWide); + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; + } - } else { + /* Get half colordepth */ + colorth = colortharray[(SiS_Pr->SiS_ModeType - ModeEGA)]; - data2 = FQBQData[i]; - data2 = (data2 & 0xf0) >> 4; - data2 <<= 24; + /* Get MCLK */ + index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A) & 0x07; + MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK; -#ifdef LINUX_KERNEL - SiS_SetRegLong(0xcf8,0x80000050); - eax = SiS_GetRegLong(0xcfc); - eax &= 0xf0ffffff; - eax |= data2; - SiS_SetRegLong(0xcfc,eax); -#else - eax = pciReadLong(0x00000000, 0x50); - eax &= 0xf0ffffff; - eax |= data2; - pciWriteLong(0x00000000, 0x50, eax); -#endif + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xc3; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3c,temp); - /* Write GUI grant timer (PCI config 0xA3) */ - data2 = FQBQData[i]; - data2 &= 0x0f; - data2 <<= 24; - -#ifdef LINUX_KERNEL - SiS_SetRegLong(0xcf8,0x800000A0); - eax = SiS_GetRegLong(0xcfc); - eax &= 0xf0ffffff; - eax |= data2; - SiS_SetRegLong(0xcfc,eax); -#else - eax = pciReadLong(0x00000000, 0xA0); - eax &= 0xf0ffffff; - eax |= data2; - pciWriteLong(0x00000000, 0xA0, eax); -#endif + do { + ThresholdLow = SiS_CalcDelay(SiS_Pr, VCLK, colorth, MCLK) + 1; + if(ThresholdLow < 0x13) break; + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x16,0xfc); + ThresholdLow = 0x13; + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) >> 6; + if(!temp) break; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3f,((temp - 1) << 6)); + } while(0); - } + } else ThresholdLow = 2; - /* Write CRT/CPU threshold low, CRT/Engine threshold high */ - data = ((ThresholdLow & 0x0f) << 4) | 0x0f; - SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,data); + /* Write CRT/CPU threshold low, CRT/Engine threshold high */ + temp = (ThresholdLow << 4) | 0x0f; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,temp); - data = (ThresholdLow & 0x10) << 1; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xDF,data); + temp = (ThresholdLow & 0x10) << 1; + if(ModeNo > 0x13) temp |= 0x40; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0f,0x9f,temp); - /* What is this? */ - SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09); + /* What is this? */ + SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09); - /* Write CRT/CPU threshold high (gap = 3) */ - data = ThresholdLow + 3; - if(data > 0x0f) data = 0x0f; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data); + /* Write CRT/CPU threshold high */ + temp = ThresholdLow + 3; + if(temp > 0x0f) temp = 0x0f; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x09,temp); } -#endif -#ifdef SIS315H -static void -SiS_SetCRT1FIFO_310(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo) +unsigned short +SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index) { - USHORT modeflag; - - /* disable auto-threshold */ - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE); - - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } - - SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE); - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0); - if(ModeNo > 0x13) { - if(HwInfo->jChipType >= SIS_661) { - if(!(modeflag & HalfDCLK)) { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); - } - } else { - if((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); - } - } - } + static const unsigned char LatencyFactor[] = { + 97, 88, 86, 79, 77, 0, /* 64 bit BQ=2 */ + 0, 87, 85, 78, 76, 54, /* 64 bit BQ=1 */ + 97, 88, 86, 79, 77, 0, /* 128 bit BQ=2 */ + 0, 79, 77, 70, 68, 48, /* 128 bit BQ=1 */ + 80, 72, 69, 63, 61, 0, /* 64 bit BQ=2 */ + 0, 70, 68, 61, 59, 37, /* 64 bit BQ=1 */ + 86, 77, 75, 68, 66, 0, /* 128 bit BQ=2 */ + 0, 68, 66, 59, 57, 37 /* 128 bit BQ=1 */ + }; + static const unsigned char LatencyFactor730[] = { + 69, 63, 61, + 86, 79, 77, + 103, 96, 94, + 120,113,111, + 137,130,128 + }; + + if(SiS_Pr->ChipType == SIS_730) { + return (unsigned short)LatencyFactor730[index]; + } else { + return (unsigned short)LatencyFactor[index]; + } } -#endif -/*********************************************/ -/* MODE REGISTERS */ -/*********************************************/ +static unsigned short +SiS_CalcDelay2(struct SiS_Private *SiS_Pr, unsigned char key) +{ + unsigned short index; + + if(SiS_Pr->ChipType == SIS_730) { + index = ((key & 0x0f) * 3) + ((key & 0xc0) >> 6); + } else { + index = (key & 0xe0) >> 5; + if(key & 0x10) index += 6; + if(!(key & 0x01)) index += 24; + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x80) index += 12; + } + return SiS_GetLatencyFactor630(SiS_Pr, index); +} static void -SiS_SetVCLKState(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo, USHORT RefreshRateTableIndex, - USHORT ModeIdIndex) +SiS_SetCRT1FIFO_630(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short RefreshRateTableIndex) { - USHORT data=0, VCLK=0, index=0; + unsigned short ThresholdLow = 0; + unsigned short i, data, VCLK, MCLK16, colorth = 0; + unsigned int templ, datal; + const unsigned char *queuedata = NULL; + static const unsigned char FQBQData[21] = { + 0x01,0x21,0x41,0x61,0x81, + 0x31,0x51,0x71,0x91,0xb1, + 0x00,0x20,0x40,0x60,0x80, + 0x30,0x50,0x70,0x90,0xb0, + 0xff + }; + static const unsigned char FQBQData730[16] = { + 0x34,0x74,0xb4, + 0x23,0x63,0xa3, + 0x12,0x52,0x92, + 0x01,0x41,0x81, + 0x00,0x40,0x80, + 0xff + }; + static const unsigned short colortharray[6] = { + 1, 1, 2, 2, 3, 4 + }; + + i = 0; - if(ModeNo > 0x13) { - if(SiS_Pr->UseCustomMode) { - VCLK = SiS_Pr->CSRClock; - } else { - index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex, - RefreshRateTableIndex,HwInfo); - VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; - } - } + if(ModeNo > 0x13) { + + /* Get VCLK */ + if(SiS_Pr->UseCustomMode) { + VCLK = SiS_Pr->CSRClock; + } else { + data = SiS_GetRefCRTVCLK(SiS_Pr, RefreshRateTableIndex, SiS_Pr->SiS_UseWide); + VCLK = SiS_Pr->SiS_VCLKData[data].CLOCK; + } - if(HwInfo->jChipType < SIS_315H) { + /* Get MCLK * 16 */ + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A) & 0x07; + MCLK16 = SiS_Pr->SiS_MCLKData_0[data].CLOCK * 16; - if(VCLK > 150) data |= 0x80; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data); + /* Get half colordepth */ + colorth = colortharray[(SiS_Pr->SiS_ModeType - ModeEGA)]; - data = 0x00; - if(VCLK >= 150) data |= 0x08; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data); + if(SiS_Pr->ChipType == SIS_730) { + queuedata = &FQBQData730[0]; + } else { + queuedata = &FQBQData[0]; + } - } else { + do { + templ = SiS_CalcDelay2(SiS_Pr, queuedata[i]) * VCLK * colorth; - if(VCLK >= 166) data |= 0x0c; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data); + datal = templ % MCLK16; + templ = (templ / MCLK16) + 1; + if(datal) templ++; - if(VCLK >= 166) { - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7); - } - } + if(templ > 0x13) { + if(queuedata[i + 1] == 0xFF) { + ThresholdLow = 0x13; + break; + } + i++; + } else { + ThresholdLow = templ; + break; + } + } while(queuedata[i] != 0xFF); - /* DAC speed */ - if(HwInfo->jChipType >= SIS_661) { + } else { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xE8,0x10); + if(SiS_Pr->ChipType != SIS_730) i = 9; + ThresholdLow = 0x02; - } else { + } - data = 0x03; - if((VCLK >= 135) && (VCLK < 160)) data = 0x02; - else if((VCLK >= 160) && (VCLK < 260)) data = 0x01; - else if(VCLK >= 260) data = 0x00; + /* Write CRT/CPU threshold low, CRT/Engine threshold high */ + data = ((ThresholdLow & 0x0f) << 4) | 0x0f; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,data); - if(HwInfo->jChipType == SIS_540) { - if((VCLK == 203) || (VCLK < 234)) data = 0x02; - } + data = (ThresholdLow & 0x10) << 1; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xDF,data); - if(HwInfo->jChipType < SIS_315H) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data); - } else { - if(HwInfo->jChipType > SIS_315PRO) { - if(ModeNo > 0x13) data &= 0xfc; - } - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data); - } + /* What is this? */ + SiS_SetReg(SiS_Pr->SiS_P3c4,0x3B,0x09); - } -} + /* Write CRT/CPU threshold high (gap = 3) */ + data = ThresholdLow + 3; + if(data > 0x0f) data = 0x0f; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data); -static void -SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex) -{ - USHORT data,infoflag=0,modeflag; - USHORT resindex,xres; -#ifdef SIS315H - USHORT data2,data3; - ULONG longdata; - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + /* Write foreground and background queue */ +#ifdef SIS_LINUX_KERNEL + templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50); +#else + templ = pciReadLong(0x00000000, 0x50); #endif - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - infoflag = SiS_Pr->CInfoFlag; - xres = SiS_Pr->CHDisplay; - } else { - resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex); - if(ModeNo > 0x13) { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; - xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal; - } else { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - xres = SiS_Pr->SiS_StResInfo[resindex].HTotal; - } - } - - /* Disable DPMS */ - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F); - - data = 0; - if(ModeNo > 0x13) { - if(SiS_Pr->SiS_ModeType > ModeEGA) { - data |= 0x02; - data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); - } - if(infoflag & InterlaceMode) data |= 0x20; - } - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data); - - if(HwInfo->jChipType != SIS_300) { - data = 0; - if(infoflag & InterlaceMode) { - if(xres <= 800) data = 0x0020; - else if(xres <= 1024) data = 0x0035; - else data = 0x0048; - } - SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,(data & 0xFF)); - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,(data >> 8)); - } - - if(modeflag & HalfDCLK) { - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08); - } - - data = 0; - if(modeflag & LineCompareOff) data = 0x08; - if(HwInfo->jChipType == SIS_300) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xF7,data); - } else { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data); - if(SiS_Pr->SiS_ModeType == ModeEGA) { - if(ModeNo > 0x13) { - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x40); - } - } - } - - if(HwInfo->jChipType >= SIS_661) { - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb); - } + if(SiS_Pr->ChipType == SIS_730) { -#ifdef SIS315H - if(HwInfo->jChipType == SIS_315PRO) { - - data = SiS_Get310DRAMType(SiS_Pr, HwInfo); - data = SiS_Pr->SiS_SR15[2][data]; - if(SiS_Pr->SiS_ModeType == ModeText) { - data &= 0xc7; - } else { - data2 = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex, - RefreshRateTableIndex,HwInfo); - data2 >>= 1; - if(infoflag & InterlaceMode) data2 >>= 1; - data3 = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex) >> 1; - if(!data3) data3++; - data2 /= data3; - if(data2 >= 0x50) { - data &= 0x0f; - data |= 0x50; - } - } - SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); - - } else if( (HwInfo->jChipType == SIS_330) || - ((HwInfo->jChipType == SIS_760) && (SiS_Pr->SiS_SysFlags & SF_760LFB))) { - - data = SiS_Get310DRAMType(SiS_Pr, HwInfo); - if(HwInfo->jChipType == SIS_330) { - data = SiS_Pr->SiS_SR15[2][data]; - } else { - if(SiS_Pr->SiS_ROMNew) data = ROMAddr[0xf6]; - else if(SiS_Pr->SiS_UseROM) data = ROMAddr[0x100 + data]; - else data = 0xba; - } - if(SiS_Pr->SiS_ModeType <= ModeEGA) { - data &= 0xc7; - } else { - if(SiS_Pr->UseCustomMode) { - data2 = SiS_Pr->CSRClock; - } else { - data2 = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex, - RefreshRateTableIndex,HwInfo); - data2 = SiS_Pr->SiS_VCLKData[data2].CLOCK; - } + templ &= 0xfffff9ff; + templ |= ((queuedata[i] & 0xc0) << 3); - data3 = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex) >> 1; - if(data3) data2 *= data3; - - longdata = SiS_GetMCLK(SiS_Pr, HwInfo) * 1024; - - data2 = longdata / data2; - - if(HwInfo->jChipType == SIS_330) { - if(SiS_Pr->SiS_ModeType != Mode16Bpp) { - if (data2 >= 0x19c) data = 0xba; - else if(data2 >= 0x140) data = 0x7a; - else if(data2 >= 0x101) data = 0x3a; - else if(data2 >= 0xf5) data = 0x32; - else if(data2 >= 0xe2) data = 0x2a; - else if(data2 >= 0xc4) data = 0x22; - else if(data2 >= 0xac) data = 0x1a; - else if(data2 >= 0x9e) data = 0x12; - else if(data2 >= 0x8e) data = 0x0a; - else data = 0x02; - } else { - if(data2 >= 0x127) data = 0xba; - else data = 0x7a; - } - } else { /* 760+LFB */ - if (data2 >= 0x190) data = 0xba; - else if(data2 >= 0xff) data = 0x7a; - else if(data2 >= 0xd3) data = 0x3a; - else if(data2 >= 0xa9) data = 0x1a; - else if(data2 >= 0x93) data = 0x0a; - else data = 0x02; - } - } - SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); - } else if(HwInfo->jChipType == SIS_340) { - /* TODO */ - } + } else { + + templ &= 0xf0ffffff; + if( (ModeNo <= 0x13) && + (SiS_Pr->ChipType == SIS_630) && + (SiS_Pr->ChipRevision >= 0x30) ) { + templ |= 0x0b000000; + } else { + templ |= ((queuedata[i] & 0xf0) << 20); + } + + } + +#ifdef SIS_LINUX_KERNEL + sisfb_write_nbridge_pci_dword(SiS_Pr, 0x50, templ); + templ = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xA0); +#else + pciWriteLong(0x00000000, 0x50, templ); + templ = pciReadLong(0x00000000, 0xA0); #endif - data = 0x60; - if(SiS_Pr->SiS_ModeType != ModeText) { - data ^= 0x60; - if(SiS_Pr->SiS_ModeType != ModeEGA) { - data ^= 0xA0; - } - } - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x21,0x1F,data); + /* GUI grant timer (PCI config 0xA3) */ + if(SiS_Pr->ChipType == SIS_730) { - SiS_SetVCLKState(SiS_Pr, HwInfo, ModeNo, RefreshRateTableIndex, ModeIdIndex); + templ &= 0x00ffffff; + datal = queuedata[i] << 8; + templ |= (((datal & 0x0f00) | ((datal & 0x3000) >> 8)) << 20); -#ifdef SIS315H - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) { - SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x2c); - } else { - SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x6c); - } - } + } else { + + templ &= 0xf0ffffff; + templ |= ((queuedata[i] & 0x0f) << 24); + + } + +#ifdef SIS_LINUX_KERNEL + sisfb_write_nbridge_pci_dword(SiS_Pr, 0xA0, templ); +#else + pciWriteLong(0x00000000, 0xA0, templ); #endif } +#endif /* SIS300 */ + +#ifdef SIS315H +static void +SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short modeflag; + + /* disable auto-threshold */ + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE); + + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0); + if(ModeNo > 0x13) { + if(SiS_Pr->ChipType >= XGI_20) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); + } else if(SiS_Pr->ChipType >= SIS_661) { + if(!(modeflag & HalfDCLK)) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); + } + } else { + if((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); + } + } + } +} +#endif /*********************************************/ -/* LOAD DAC */ +/* MODE REGISTERS */ /*********************************************/ -#if 0 static void -SiS_ClearDAC(SiS_Private *SiS_Pr, ULONG port) +SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short RefreshRateTableIndex, unsigned short ModeIdIndex) +{ + unsigned short data = 0, VCLK = 0, index = 0; + + if(ModeNo > 0x13) { + if(SiS_Pr->UseCustomMode) { + VCLK = SiS_Pr->CSRClock; + } else { + index = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; + } + } + + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef SIS300 + if(VCLK > 150) data |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data); + + data = 0x00; + if(VCLK >= 150) data |= 0x08; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data); +#endif + } else if(SiS_Pr->ChipType < XGI_20) { +#ifdef SIS315H + if(VCLK >= 166) data |= 0x0c; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data); + + if(VCLK >= 166) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7); + } +#endif + } else { +#ifdef SIS315H + if(VCLK >= 200) data |= 0x0c; + if(SiS_Pr->ChipType == XGI_20) data &= ~0x04; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data); + if(SiS_Pr->ChipType != XGI_20) { + data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f) & 0xe7; + if(VCLK < 200) data |= 0x10; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x1f,data); + } +#endif + } + + /* DAC speed */ + if(SiS_Pr->ChipType >= SIS_661) { + + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xE8,0x10); + + } else { + + data = 0x03; + if(VCLK >= 260) data = 0x00; + else if(VCLK >= 160) data = 0x01; + else if(VCLK >= 135) data = 0x02; + + if(SiS_Pr->ChipType == SIS_540) { + if((VCLK == 203) || (VCLK < 234)) data = 0x02; + } + + if(SiS_Pr->ChipType < SIS_315H) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data); + } else { + if(SiS_Pr->ChipType > SIS_315PRO) { + if(ModeNo > 0x13) data &= 0xfc; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data); + } + + } +} + +static void +SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) +{ + unsigned short data, infoflag = 0, modeflag, resindex; +#ifdef SIS315H + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short data2, data3; +#endif + + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + } else { + resindex = SiS_GetResInfo(SiS_Pr, ModeNo, ModeIdIndex); + if(ModeNo > 0x13) { + infoflag = SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag; + } + } + + /* Disable DPMS */ + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F); + + data = 0; + if(ModeNo > 0x13) { + if(SiS_Pr->SiS_ModeType > ModeEGA) { + data |= 0x02; + data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); + } + if(infoflag & InterlaceMode) data |= 0x20; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data); + + if(SiS_Pr->ChipType != SIS_300) { + data = 0; + if(infoflag & InterlaceMode) { + /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */ + int hrs = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x04) | + ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x0b) & 0xc0) << 2)) - 3; + int hto = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x00) | + ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x0b) & 0x03) << 8)) + 5; + data = hrs - (hto >> 1) + 3; + } + SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,data); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,((data >> 8) & 0x03)); + } + + if(modeflag & HalfDCLK) { + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08); + } + + data = 0; + if(modeflag & LineCompareOff) data = 0x08; + if(SiS_Pr->ChipType == SIS_300) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xF7,data); + } else { + if(SiS_Pr->ChipType >= XGI_20) data |= 0x20; + if(SiS_Pr->SiS_ModeType == ModeEGA) { + if(ModeNo > 0x13) { + data |= 0x40; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data); + } + +#ifdef SIS315H + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb); + } + + if(SiS_Pr->ChipType == SIS_315PRO) { + + data = SiS_Pr->SiS_SR15[(2 * 4) + SiS_Get310DRAMType(SiS_Pr)]; + if(SiS_Pr->SiS_ModeType == ModeText) { + data &= 0xc7; + } else { + data2 = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, RRTI) >> 1; + if(infoflag & InterlaceMode) data2 >>= 1; + data3 = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex) >> 1; + if(data3) data2 /= data3; + if(data2 >= 0x50) { + data &= 0x0f; + data |= 0x50; + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); + + } else if((SiS_Pr->ChipType == SIS_330) || (SiS_Pr->SiS_SysFlags & SF_760LFB)) { + + data = SiS_Get310DRAMType(SiS_Pr); + if(SiS_Pr->ChipType == SIS_330) { + data = SiS_Pr->SiS_SR15[(2 * 4) + data]; + } else { + if(SiS_Pr->SiS_ROMNew) data = ROMAddr[0xf6]; + else if(SiS_Pr->SiS_UseROM) data = ROMAddr[0x100 + data]; + else data = 0xba; + } + if(SiS_Pr->SiS_ModeType <= ModeEGA) { + data &= 0xc7; + } else { + if(SiS_Pr->UseCustomMode) { + data2 = SiS_Pr->CSRClock; + } else { + data2 = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RRTI); + data2 = SiS_Pr->SiS_VCLKData[data2].CLOCK; + } + + data3 = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex) >> 1; + if(data3) data2 *= data3; + + data2 = ((unsigned int)(SiS_GetMCLK(SiS_Pr) * 1024)) / data2; + + if(SiS_Pr->ChipType == SIS_330) { + if(SiS_Pr->SiS_ModeType != Mode16Bpp) { + if (data2 >= 0x19c) data = 0xba; + else if(data2 >= 0x140) data = 0x7a; + else if(data2 >= 0x101) data = 0x3a; + else if(data2 >= 0xf5) data = 0x32; + else if(data2 >= 0xe2) data = 0x2a; + else if(data2 >= 0xc4) data = 0x22; + else if(data2 >= 0xac) data = 0x1a; + else if(data2 >= 0x9e) data = 0x12; + else if(data2 >= 0x8e) data = 0x0a; + else data = 0x02; + } else { + if(data2 >= 0x127) data = 0xba; + else data = 0x7a; + } + } else { /* 76x+LFB */ + if (data2 >= 0x190) data = 0xba; + else if(data2 >= 0xff) data = 0x7a; + else if(data2 >= 0xd3) data = 0x3a; + else if(data2 >= 0xa9) data = 0x1a; + else if(data2 >= 0x93) data = 0x0a; + else data = 0x02; + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); + + } + /* XGI: Nothing. */ + /* TODO: Check SiS340 */ +#endif + + data = 0x60; + if(SiS_Pr->SiS_ModeType != ModeText) { + data ^= 0x60; + if(SiS_Pr->SiS_ModeType != ModeEGA) { + data ^= 0xA0; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x21,0x1F,data); + + SiS_SetVCLKState(SiS_Pr, ModeNo, RRTI, ModeIdIndex); + +#ifdef SIS315H + if(((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) || + (SiS_Pr->ChipType == XGI_40)) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x2c); + } else { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x6c); + } + } else if(SiS_Pr->ChipType == XGI_20) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x33); + } else { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x73); + } + SiS_SetReg(SiS_Pr->SiS_P3d4,0x51,0x02); + } +#endif +} + +#ifdef SIS315H +static void +SiS_SetupDualChip(struct SiS_Private *SiS_Pr) { +#if 0 + /* TODO: Find out about IOAddress2 */ + SISIOADDRESS P2_3c2 = SiS_Pr->IOAddress2 + 0x12; + SISIOADDRESS P2_3c4 = SiS_Pr->IOAddress2 + 0x14; + SISIOADDRESS P2_3ce = SiS_Pr->IOAddress2 + 0x1e; int i; - OutPortByte(port, 0); - port++; - for (i=0; i < (256 * 3); i++) { - OutPortByte(port, 0); + if((SiS_Pr->ChipRevision != 0) || + (!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x3a) & 0x04))) + return; + + for(i = 0; i <= 4; i++) { /* SR00 - SR04 */ + SiS_SetReg(P2_3c4,i,SiS_GetReg(SiS_Pr->SiS_P3c4,i)); } + for(i = 0; i <= 8; i++) { /* GR00 - GR08 */ + SiS_SetReg(P2_3ce,i,SiS_GetReg(SiS_Pr->SiS_P3ce,i)); + } + SiS_SetReg(P2_3c4,0x05,0x86); + SiS_SetReg(P2_3c4,0x06,SiS_GetReg(SiS_Pr->SiS_P3c4,0x06)); /* SR06 */ + SiS_SetReg(P2_3c4,0x21,SiS_GetReg(SiS_Pr->SiS_P3c4,0x21)); /* SR21 */ + SiS_SetRegByte(P2_3c2,SiS_GetRegByte(SiS_Pr->SiS_P3cc)); /* MISC */ + SiS_SetReg(P2_3c4,0x05,0x00); +#endif } #endif +/*********************************************/ +/* LOAD DAC */ +/*********************************************/ + static void -SiS_WriteDAC(SiS_Private *SiS_Pr, SISIOADDRESS DACData, USHORT shiftflag, - USHORT dl, USHORT ah, USHORT al, USHORT dh) +SiS_WriteDAC(struct SiS_Private *SiS_Pr, SISIOADDRESS DACData, unsigned short shiftflag, + unsigned short dl, unsigned short ah, unsigned short al, unsigned short dh) { - USHORT temp,bh,bl; - - bh = ah; - bl = al; - if(dl != 0) { - temp = bh; - bh = dh; - dh = temp; - if(dl == 1) { - temp = bl; - bl = dh; - dh = temp; - } else { - temp = bl; - bl = bh; - bh = temp; - } - } - if(shiftflag) { - dh <<= 2; - bh <<= 2; - bl <<= 2; - } - SiS_SetRegByte(DACData,(USHORT)dh); - SiS_SetRegByte(DACData,(USHORT)bh); - SiS_SetRegByte(DACData,(USHORT)bl); + unsigned short d1, d2, d3; + + switch(dl) { + case 0: d1 = dh; d2 = ah; d3 = al; break; + case 1: d1 = ah; d2 = al; d3 = dh; break; + default: d1 = al; d2 = dh; d3 = ah; + } + SiS_SetRegByte(DACData, (d1 << shiftflag)); + SiS_SetRegByte(DACData, (d2 << shiftflag)); + SiS_SetRegByte(DACData, (d3 << shiftflag)); } void -SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo, USHORT ModeIdIndex) +SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - USHORT data,data2; - USHORT time,i,j,k,m,n,o; - USHORT si,di,bx,dl,al,ah,dh; - USHORT shiftflag; + unsigned short data, data2, time, i, j, k, m, n, o; + unsigned short si, di, bx, sf; SISIOADDRESS DACAddr, DACData; - const USHORT *table = NULL; + const unsigned char *table = NULL; - if(ModeNo <= 0x13) { - data = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - if(SiS_Pr->UseCustomMode) { - data = SiS_Pr->CModeFlag; - } else { - data = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } - } + data = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex) & DACInfoFlag; - data &= DACInfoFlag; - time = 64; - if(data == 0x00) table = SiS_MDA_DAC; - if(data == 0x08) table = SiS_CGA_DAC; - if(data == 0x10) table = SiS_EGA_DAC; - if(data == 0x18) { + j = time = 64; + if(data == 0x00) table = SiS_MDA_DAC; + else if(data == 0x08) table = SiS_CGA_DAC; + else if(data == 0x10) table = SiS_EGA_DAC; + else if(data == 0x18) { + j = 16; time = 256; table = SiS_VGA_DAC; } - if(time == 256) j = 16; - else j = time; if( ( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && /* 301B-DH LCD */ (SiS_Pr->SiS_VBType & VB_NoLCD) ) || (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) || /* LCDA */ (!(SiS_Pr->SiS_SetFlag & ProgrammingCRT2)) ) { /* Programming CRT1 */ + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); DACAddr = SiS_Pr->SiS_P3c8; DACData = SiS_Pr->SiS_P3c9; - shiftflag = 0; - SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); + sf = 0; } else { - shiftflag = 1; DACAddr = SiS_Pr->SiS_Part5Port; DACData = SiS_Pr->SiS_Part5Port + 1; + sf = 2; } SiS_SetRegByte(DACAddr,0x00); - for(i=0; i<j; i++) { + for(i = 0; i < j; i++) { data = table[i]; - for(k=0; k<3; k++) { + for(k = 0; k < 3; k++) { data2 = 0; - if(data & 0x01) data2 = 0x2A; + if(data & 0x01) data2 += 0x2A; if(data & 0x02) data2 += 0x15; - if(shiftflag) data2 <<= 2; - SiS_SetRegByte(DACData, data2); + SiS_SetRegByte(DACData, (data2 << sf)); data >>= 2; } } if(time == 256) { for(i = 16; i < 32; i++) { - data = table[i]; - if(shiftflag) data <<= 2; + data = table[i] << sf; for(k = 0; k < 3; k++) SiS_SetRegByte(DACData, data); } si = 32; for(m = 0; m < 9; m++) { - di = si; - bx = si + 4; - dl = 0; - for(n = 0; n < 3; n++) { - for(o = 0; o < 5; o++) { - dh = table[si]; - ah = table[di]; - al = table[bx]; + di = si; + bx = si + 4; + for(n = 0; n < 3; n++) { + for(o = 0; o < 5; o++) { + SiS_WriteDAC(SiS_Pr, DACData, sf, n, table[di], table[bx], table[si]); si++; - SiS_WriteDAC(SiS_Pr, DACData, shiftflag, dl, ah, al, dh); } si -= 2; for(o = 0; o < 3; o++) { - dh = table[bx]; - ah = table[di]; - al = table[si]; + SiS_WriteDAC(SiS_Pr, DACData, sf, n, table[di], table[si], table[bx]); si--; - SiS_WriteDAC(SiS_Pr, DACData, shiftflag, dl, ah, al, dh); } - dl++; } /* for n < 3 */ si += 5; } /* for m < 9 */ @@ -3241,89 +2972,114 @@ SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, /*********************************************/ static void -SiS_SetCRT1Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo, USHORT ModeIdIndex) +SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - USHORT StandTableIndex,RefreshRateTableIndex; - - SiS_Pr->SiS_CRT1Mode = ModeNo; - StandTableIndex = SiS_GetModePtr(SiS_Pr, ModeNo, ModeIdIndex); - if(SiS_Pr->SiS_SetFlag & LowModeTests) { - if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2)) { - SiS_DisableBridge(SiS_Pr, HwInfo); - } - } - - SiS_ResetSegmentRegisters(SiS_Pr, HwInfo); - - SiS_SetSeqRegs(SiS_Pr, StandTableIndex, HwInfo); - SiS_SetMiscRegs(SiS_Pr, StandTableIndex, HwInfo); - SiS_SetCRTCRegs(SiS_Pr, HwInfo, StandTableIndex); - SiS_SetATTRegs(SiS_Pr, StandTableIndex, HwInfo); - SiS_SetGRCRegs(SiS_Pr, StandTableIndex); - SiS_ClearExt1Regs(SiS_Pr, HwInfo, ModeNo); - SiS_ResetCRT1VCLK(SiS_Pr, HwInfo); - - SiS_Pr->SiS_SelectCRT2Rate = 0; - SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); - -#ifdef LINUX_XF86 - xf86DrvMsgVerb(0, X_PROBED, 4, "(init: VBType=0x%04x, VBInfo=0x%04x)\n", + unsigned short StandTableIndex, RefreshRateTableIndex; + + SiS_Pr->SiS_CRT1Mode = ModeNo; + + StandTableIndex = SiS_GetModePtr(SiS_Pr, ModeNo, ModeIdIndex); + + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2)) { + SiS_DisableBridge(SiS_Pr); + } + } + + SiS_ResetSegmentRegisters(SiS_Pr); + + SiS_SetSeqRegs(SiS_Pr, StandTableIndex); + SiS_SetMiscRegs(SiS_Pr, StandTableIndex); + SiS_SetCRTCRegs(SiS_Pr, StandTableIndex); + SiS_SetATTRegs(SiS_Pr, StandTableIndex); + SiS_SetGRCRegs(SiS_Pr, StandTableIndex); + SiS_ClearExt1Regs(SiS_Pr, ModeNo); + SiS_ResetCRT1VCLK(SiS_Pr); + + SiS_Pr->SiS_SelectCRT2Rate = 0; + SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); + +#ifdef SIS_XORG_XF86 + xf86DrvMsgVerb(0, X_PROBED, 4, "(init: VBType=0x%04x, VBInfo=0x%04x)\n", SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo); #endif - if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; - } - } + if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + } + } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; - } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + } - RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex); - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { - SiS_Pr->SiS_SetFlag &= ~ProgrammingCRT2; - } + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_Pr->SiS_SetFlag &= ~ProgrammingCRT2; + } - if(RefreshRateTableIndex != 0xFFFF) { - SiS_SetCRT1Sync(SiS_Pr, RefreshRateTableIndex); - SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - SiS_SetCRT1VCLK(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); - } + if(RefreshRateTableIndex != 0xFFFF) { + SiS_SetCRT1Sync(SiS_Pr, RefreshRateTableIndex); + SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + SiS_SetCRT1VCLK(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + switch(SiS_Pr->ChipType) { #ifdef SIS300 - if(HwInfo->jChipType == SIS_300) { - SiS_SetCRT1FIFO_300(SiS_Pr, ModeNo,HwInfo,RefreshRateTableIndex); - } else if((HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730) || - (HwInfo->jChipType == SIS_540)) { - SiS_SetCRT1FIFO_630(SiS_Pr, ModeNo, HwInfo, RefreshRateTableIndex); - } + case SIS_300: + SiS_SetCRT1FIFO_300(SiS_Pr, ModeNo, RefreshRateTableIndex); + break; + case SIS_540: + case SIS_630: + case SIS_730: + SiS_SetCRT1FIFO_630(SiS_Pr, ModeNo, RefreshRateTableIndex); + break; #endif + default: #ifdef SIS315H - if(HwInfo->jChipType >= SIS_315H) { - SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); - } + if(SiS_Pr->ChipType == XGI_20) { + unsigned char sr2b = 0, sr2c = 0; + switch(ModeNo) { + case 0x00: + case 0x01: sr2b = 0x4e; sr2c = 0xe9; break; + case 0x04: + case 0x05: + case 0x0d: sr2b = 0x1b; sr2c = 0xe3; break; + } + if(sr2b) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2b,sr2b); + SiS_SetReg(SiS_Pr->SiS_P3c4,0x2c,sr2c); + SiS_SetRegByte(SiS_Pr->SiS_P3c2,(SiS_GetRegByte(SiS_Pr->SiS_P3cc) | 0x0c)); + } + } + SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex); #endif + break; + } + + SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); - SiS_SetCRT1ModeRegs(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex); +#ifdef SIS315H + if(SiS_Pr->ChipType == XGI_40) { + SiS_SetupDualChip(SiS_Pr); + } +#endif - SiS_LoadDAC(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); + SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex); -#ifdef LINUX_KERNEL - if(SiS_Pr->SiS_flag_clearbuffer) { - SiS_ClearBuffer(SiS_Pr,HwInfo,ModeNo); - } +#ifdef SIS_LINUX_KERNEL + if(SiS_Pr->SiS_flag_clearbuffer) { + SiS_ClearBuffer(SiS_Pr, ModeNo); + } #endif - if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA))) { - SiS_WaitRetrace1(SiS_Pr); - SiS_DisplayOn(SiS_Pr); - } + if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA))) { + SiS_WaitRetrace1(SiS_Pr); + SiS_DisplayOn(SiS_Pr); + } } /*********************************************/ @@ -3331,33 +3087,62 @@ SiS_SetCRT1Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, /*********************************************/ static void -SiS_ResetVB(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_InitVB(struct SiS_Private *SiS_Pr) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + + SiS_Pr->Init_P4_0E = 0; + if(SiS_Pr->SiS_ROMNew) { + SiS_Pr->Init_P4_0E = ROMAddr[0x82]; + } else if(SiS_Pr->ChipType >= XGI_40) { + if(SiS_Pr->SiS_XGIROM) { + SiS_Pr->Init_P4_0E = ROMAddr[0x80]; + } + } +} + +static void +SiS_ResetVB(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT temp; +#ifdef SIS315H + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short temp; /* VB programming clock */ if(SiS_Pr->SiS_UseROM) { - if(HwInfo->jChipType < SIS_330) { - temp = ROMAddr[VB310Data_1_2_Offset] | 0x40; + if(SiS_Pr->ChipType < SIS_330) { + temp = ROMAddr[VB310Data_1_2_Offset] | 0x40; if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); - } else if(HwInfo->jChipType >= SIS_661) { - temp = ROMAddr[0x7e] | 0x40; - if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40; + } else if(SiS_Pr->ChipType >= SIS_661 && SiS_Pr->ChipType < XGI_20) { + temp = ROMAddr[0x7e] | 0x40; + if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); } + } else if(SiS_Pr->ChipType >= XGI_40) { + temp = 0x40; + if(SiS_Pr->SiS_XGIROM) temp |= ROMAddr[0x7e]; + /* Can we do this on any chipset? */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); } +#endif } /*********************************************/ -/* HELPER: SET VIDEO REGISTERS */ +/* HELPER: SET VIDEO/CAPTURE REGISTERS */ /*********************************************/ static void -SiS_StrangeStuff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_StrangeStuff(struct SiS_Private *SiS_Pr) { - if((IS_SIS651) || (IS_SISM650)) { + /* SiS65x and XGI set up some sort of "lock mode" for text + * which locks CRT2 in some way to CRT1 timing. Disable + * this here. + */ +#ifdef SIS315H + if((IS_SIS651) || (IS_SISM650) || + SiS_Pr->ChipType == SIS_340 || + SiS_Pr->ChipType == XGI_40) { SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x3f, 0x00); /* Fiddle with capture regs */ SiS_SetReg(SiS_Pr->SiS_VidCapt, 0x00, 0x00); SiS_SetReg(SiS_Pr->SiS_VidPlay, 0x00, 0x86); /* (BIOS does NOT unlock) */ @@ -3365,49 +3150,99 @@ SiS_StrangeStuff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_SetRegAND(SiS_Pr->SiS_VidPlay, 0x3f, 0xef); } /* !!! This does not support modes < 0x13 !!! */ +#endif +} + +/*********************************************/ +/* HELPER: SET AGP TIMING FOR SiS760 */ +/*********************************************/ + +static void +SiS_Handle760(struct SiS_Private *SiS_Pr) +{ +#ifdef SIS315H + unsigned int somebase; + unsigned char temp1, temp2, temp3; + + if( (SiS_Pr->ChipType != SIS_760) || + ((SiS_GetReg(SiS_Pr->SiS_P3d4, 0x5c) & 0xf8) != 0x80) || + (!(SiS_Pr->SiS_SysFlags & SF_760LFB)) || + (!(SiS_Pr->SiS_SysFlags & SF_760UMA)) ) + return; + +#ifdef SIS_LINUX_KERNEL + somebase = sisfb_read_mio_pci_word(SiS_Pr, 0x74); +#else + somebase = pciReadWord(0x00001000, 0x74); +#endif + somebase &= 0xffff; + + if(somebase == 0) return; + + temp3 = SiS_GetRegByte((somebase + 0x85)) & 0xb7; + + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40) { + temp1 = 0x21; + temp2 = 0x03; + temp3 |= 0x08; + } else { + temp1 = 0x25; + temp2 = 0x0b; + } + +#ifdef SIS_LINUX_KERNEL + sisfb_write_nbridge_pci_byte(SiS_Pr, 0x7e, temp1); + sisfb_write_nbridge_pci_byte(SiS_Pr, 0x8d, temp2); +#else + pciWriteByte(0x00000000, 0x7e, temp1); + pciWriteByte(0x00000000, 0x8d, temp2); +#endif + + SiS_SetRegByte((somebase + 0x85), temp3); +#endif } /*********************************************/ -/* XFree86: SET SCREEN PITCH */ +/* X.org/XFree86: SET SCREEN PITCH */ /*********************************************/ -#ifdef LINUX_XF86 +#ifdef SIS_XORG_XF86 static void -SiS_SetPitchCRT1(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) +SiS_SetPitchCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); - UShort HDisplay = pSiS->scrnPitch >> 3; + unsigned short HDisplay = pSiS->scrnPitch >> 3; SiS_SetReg(SiS_Pr->SiS_P3d4,0x13,(HDisplay & 0xFF)); - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,(HDisplay>>8)); + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,(HDisplay >> 8)); } static void -SiS_SetPitchCRT2(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) +SiS_SetPitchCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); - UShort HDisplay = pSiS->scrnPitch2 >> 3; + unsigned short HDisplay = pSiS->scrnPitch2 >> 3; /* Unlock CRT2 */ if(pSiS->VGAEngine == SIS_315_VGA) - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2F, 0x01); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2F, 0x01); else - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24, 0x01); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24, 0x01); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(HDisplay & 0xFF)); SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0xF0,(HDisplay >> 8)); } static void -SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) +SiS_SetPitch(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); BOOLEAN isslavemode = FALSE; - if( (pSiS->VBFlags & VB_VIDEOBRIDGE) && + if( (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) && ( ((pSiS->VGAEngine == SIS_300_VGA) && - (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) || - ((pSiS->VGAEngine == SIS_315_VGA) && + (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) || + ((pSiS->VGAEngine == SIS_315_VGA) && (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) { isslavemode = TRUE; } @@ -3427,59 +3262,59 @@ SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn) /* SiSSetMode() */ /*********************************************/ -#ifdef LINUX_XF86 +#ifdef SIS_XORG_XF86 /* We need pScrn for setting the pitch correctly */ BOOLEAN -SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch) +SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo, BOOLEAN dosetpitch) #else BOOLEAN -SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo) +SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) #endif { - USHORT ModeIdIndex; - SISIOADDRESS BaseAddr = HwInfo->ulIOAddress; - unsigned char backupreg=0; -#ifdef LINUX_KERNEL - USHORT KeepLockReg; - ULONG temp; + SISIOADDRESS BaseAddr = SiS_Pr->IOAddress; + unsigned short RealModeNo, ModeIdIndex; + unsigned char backupreg = 0; +#ifdef SIS_LINUX_KERNEL + unsigned short KeepLockReg; SiS_Pr->UseCustomMode = FALSE; SiS_Pr->CRT1UsesCustomMode = FALSE; #endif + SiS_Pr->SiS_flag_clearbuffer = 0; + if(SiS_Pr->UseCustomMode) { ModeNo = 0xfe; + } else { +#ifdef SIS_LINUX_KERNEL + if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1; +#endif + ModeNo &= 0x7f; } - SiSInitPtr(SiS_Pr, HwInfo); + /* Don't use FSTN mode for CRT1 */ + RealModeNo = ModeNo; + if(ModeNo == 0x5b) ModeNo = 0x56; + + SiSInitPtr(SiS_Pr); SiSRegInit(SiS_Pr, BaseAddr); - SiS_GetSysFlags(SiS_Pr, HwInfo); + SiS_GetSysFlags(SiS_Pr); -#if defined(LINUX_XF86) && (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__)) + SiS_Pr->SiS_VGAINFO = 0x11; +#if defined(SIS_XORG_XF86) && (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__)) if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); - else -#endif - SiS_Pr->SiS_VGAINFO = 0x11; - - SiSInitPCIetc(SiS_Pr, HwInfo); - SiSSetLVDSetc(SiS_Pr, HwInfo); - SiSDetermineROMUsage(SiS_Pr, HwInfo); - - SiS_Pr->SiS_flag_clearbuffer = 0; - - if(!SiS_Pr->UseCustomMode) { -#ifdef LINUX_KERNEL - if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1; #endif - ModeNo &= 0x7f; - } -#ifdef LINUX_KERNEL +#ifdef SIS_LINUX_KERNEL KeepLockReg = SiS_GetReg(SiS_Pr->SiS_P3c4,0x05); #endif SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); - SiS_UnLockCRT2(SiS_Pr, HwInfo); + SiSInitPCIetc(SiS_Pr); + SiSSetLVDSetc(SiS_Pr); + SiSDetermineROMUsage(SiS_Pr); + + SiS_UnLockCRT2(SiS_Pr); if(!SiS_Pr->UseCustomMode) { if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE; @@ -3487,13 +3322,13 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo) ModeIdIndex = 0; } - SiS_GetVBType(SiS_Pr, HwInfo); + SiS_GetVBType(SiS_Pr); /* Init/restore some VB registers */ - - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(HwInfo->jChipType >= SIS_315H) { - SiS_ResetVB(SiS_Pr, HwInfo); + SiS_InitVB(SiS_Pr); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_ResetVB(SiS_Pr); SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10); SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c); backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); @@ -3503,21 +3338,20 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo) } /* Get VB information (connectors, connected devices) */ - SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, (SiS_Pr->UseCustomMode) ? 0 : 1); - SiS_SetYPbPr(SiS_Pr, HwInfo); - SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); - SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); - SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo); - -#ifdef LINUX_KERNEL - /* 3. Check memory size (Kernel framebuffer driver only) */ - temp = SiS_CheckMemorySize(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); - if(!temp) return(0); + SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, (SiS_Pr->UseCustomMode) ? 0 : 1); + SiS_SetYPbPr(SiS_Pr); + SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex); + SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex); + SiS_SetLowModeTest(SiS_Pr, ModeNo); + +#ifdef SIS_LINUX_KERNEL + /* Check memory size (kernel framebuffer driver only) */ + if(!SiS_CheckMemorySize(SiS_Pr, ModeNo, ModeIdIndex)) { + return FALSE; + } #endif - if(HwInfo->jChipType >= SIS_315H) { - SiS_SetupCR5x(SiS_Pr, HwInfo); - } + SiS_OpenCRTC(SiS_Pr); if(SiS_Pr->UseCustomMode) { SiS_Pr->CRT1UsesCustomMode = TRUE; @@ -3530,38 +3364,41 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo) /* Set mode on CRT1 */ if( (SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) || (!(SiS_Pr->SiS_VBInfo & SwitchCRT2)) ) { - SiS_SetCRT1Group(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); + SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex); } /* Set mode on CRT2 */ if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchCRT2 | SetCRT2ToLCDA)) { if( (SiS_Pr->SiS_VBType & VB_SISVB) || - (SiS_Pr->SiS_IF_DEF_LVDS == 1) || - (SiS_Pr->SiS_IF_DEF_CH70xx != 0) || - (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) { - SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo); + (SiS_Pr->SiS_IF_DEF_LVDS == 1) || + (SiS_Pr->SiS_IF_DEF_CH70xx != 0) || + (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) { + SiS_SetCRT2Group(SiS_Pr, RealModeNo); } } SiS_HandleCRT1(SiS_Pr); - SiS_StrangeStuff(SiS_Pr, HwInfo); + SiS_StrangeStuff(SiS_Pr); SiS_DisplayOn(SiS_Pr); SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); - if(HwInfo->jChipType >= SIS_315H) { +#ifdef SIS315H + if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) { + if(!(SiS_IsDualEdge(SiS_Pr))) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); } } } +#endif - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(HwInfo->jChipType >= SIS_315H) { - if(!SiS_Pr->SiS_ROMNew) { - if(SiS_IsVAMode(SiS_Pr,HwInfo)) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->ChipType >= SIS_315H) { +#ifdef SIS315H + if(!SiS_Pr->SiS_ROMNew) { + if(SiS_IsVAMode(SiS_Pr)) { SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); } else { SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE); @@ -3574,23 +3411,24 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo) if((ModeNo == 0x03) || (ModeNo == 0x10)) { SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x80); SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x56,0x08); - } + } } if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) { SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); } - } else if((HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730)) { - SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg); +#endif + } else if((SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730)) { + SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg); } } -#ifdef LINUX_XF86 +#ifdef SIS_XORG_XF86 if(pScrn) { /* SetPitch: Adapt to virtual size & position */ if((ModeNo > 0x13) && (dosetpitch)) { - SiS_SetPitch(SiS_Pr, pScrn); + SiS_SetPitch(SiS_Pr, pScrn); } /* Backup/Set ModeNo in BIOS scratch area */ @@ -3598,33 +3436,37 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo) } #endif -#ifdef LINUX_KERNEL /* We never lock registers in XF86 */ - if(KeepLockReg == 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); - else SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00); + SiS_CloseCRTC(SiS_Pr); + + SiS_Handle760(SiS_Pr); + +#ifdef SIS_LINUX_KERNEL + /* We never lock registers in XF86 */ + if(KeepLockReg != 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00); #endif return TRUE; } /*********************************************/ -/* XFree86: SiSBIOSSetMode() */ +/* X.org/XFree86: SiSBIOSSetMode() */ /* for non-Dual-Head mode */ /*********************************************/ -#ifdef LINUX_XF86 +#ifdef SIS_XORG_XF86 BOOLEAN -SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, +SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom) { SISPtr pSiS = SISPTR(pScrn); - UShort ModeNo = 0; + unsigned short ModeNo = 0; SiS_Pr->UseCustomMode = FALSE; if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) { xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d\n", - SiS_Pr->CHDisplay, + SiS_Pr->CHDisplay, (mode->Flags & V_INTERLACE ? SiS_Pr->CVDisplay * 2 : (mode->Flags & V_DBLSCAN ? SiS_Pr->CVDisplay / 2 : SiS_Pr->CVDisplay))); @@ -3632,32 +3474,33 @@ SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, } else { /* Don't need vbflags here; checks done earlier */ - ModeNo = SiS_GetModeNumber(pScrn, mode, 0); + ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags); if(!ModeNo) return FALSE; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo); } - return(SiSSetMode(SiS_Pr, HwInfo, pScrn, ModeNo, TRUE)); + return(SiSSetMode(SiS_Pr, pScrn, ModeNo, TRUE)); } /*********************************************/ -/* XFree86: SiSBIOSSetModeCRT2() */ +/* X.org/XFree86: SiSBIOSSetModeCRT2() */ /* for Dual-Head modes */ /*********************************************/ + BOOLEAN -SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, +SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom) { - USHORT ModeIdIndex; - SISIOADDRESS BaseAddr = HwInfo->ulIOAddress; - UShort ModeNo = 0; - unsigned char backupreg=0; - SISPtr pSiS = SISPTR(pScrn); + SISIOADDRESS BaseAddr = SiS_Pr->IOAddress; + SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; #endif + unsigned short ModeIdIndex; + unsigned short ModeNo = 0; + unsigned char backupreg = 0; SiS_Pr->UseCustomMode = FALSE; @@ -3672,22 +3515,25 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, } else { - ModeNo = SiS_GetModeNumber(pScrn, mode, 0); - if(!ModeNo) return FALSE; + ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags); + if(!ModeNo) return FALSE; } SiSRegInit(SiS_Pr, BaseAddr); - SiSInitPtr(SiS_Pr, HwInfo); - SiS_GetSysFlags(SiS_Pr, HwInfo); -#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__)) + SiSInitPtr(SiS_Pr); + SiS_GetSysFlags(SiS_Pr); +#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); #else SiS_Pr->SiS_VGAINFO = 0x11; #endif - SiSInitPCIetc(SiS_Pr, HwInfo); - SiSSetLVDSetc(SiS_Pr, HwInfo); - SiSDetermineROMUsage(SiS_Pr, HwInfo); + + SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); + + SiSInitPCIetc(SiS_Pr); + SiSSetLVDSetc(SiS_Pr); + SiSDetermineROMUsage(SiS_Pr); /* Save mode info so we can set it from within SetMode for CRT1 */ #ifdef SISDUALHEAD @@ -3700,23 +3546,20 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, pSiSEnt->CRT2CR35 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); pSiSEnt->CRT2CR38 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); #if 0 - /* We can't set CRT2 mode before CRT1 mode is set */ + /* We can't set CRT2 mode before CRT1 mode is set - says who...? */ if(pSiSEnt->CRT1ModeNo == -1) { - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting CRT2 mode delayed until after setting CRT1 mode\n"); - return TRUE; + return TRUE; } #endif pSiSEnt->CRT2ModeSet = TRUE; } #endif - /* We don't clear the buffer in X */ - SiS_Pr->SiS_flag_clearbuffer=0; - if(SiS_Pr->UseCustomMode) { - USHORT temptemp = SiS_Pr->CVDisplay; + unsigned short temptemp = SiS_Pr->CVDisplay; if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1; else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1; @@ -3728,13 +3571,11 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, } else { xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, - "Setting standard mode 0x%x on CRT2\n", ModeNo); + "Setting standard mode 0x%x on CRT2\n", ModeNo); } - SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); - - SiS_UnLockCRT2(SiS_Pr, HwInfo); + SiS_UnLockCRT2(SiS_Pr); if(!SiS_Pr->UseCustomMode) { if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE; @@ -3742,56 +3583,59 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, ModeIdIndex = 0; } - SiS_GetVBType(SiS_Pr, HwInfo); + SiS_GetVBType(SiS_Pr); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(HwInfo->jChipType >= SIS_315H) { - SiS_ResetVB(SiS_Pr, HwInfo); + SiS_InitVB(SiS_Pr); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_ResetVB(SiS_Pr); SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10); SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c); - backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); } else { - backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); } } /* Get VB information (connectors, connected devices) */ if(!SiS_Pr->UseCustomMode) { - SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 1); + SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 1); } else { /* If this is a custom mode, we don't check the modeflag for CRT2Mode */ - SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 0); + SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 0); } - SiS_SetYPbPr(SiS_Pr, HwInfo); - SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); - SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); - SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo); + SiS_SetYPbPr(SiS_Pr); + SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex); + SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex); + SiS_SetLowModeTest(SiS_Pr, ModeNo); + + SiS_ResetSegmentRegisters(SiS_Pr); /* Set mode on CRT2 */ if( (SiS_Pr->SiS_VBType & VB_SISVB) || (SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_IF_DEF_CH70xx != 0) || (SiS_Pr->SiS_IF_DEF_TRUMPION != 0) ) { - SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo); + SiS_SetCRT2Group(SiS_Pr, ModeNo); } - SiS_StrangeStuff(SiS_Pr, HwInfo); + SiS_StrangeStuff(SiS_Pr); SiS_DisplayOn(SiS_Pr); SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) { + if(!(SiS_IsDualEdge(SiS_Pr))) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); } } } - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(HwInfo->jChipType >= SIS_315H) { - if(!SiS_Pr->SiS_ROMNew) { - if(SiS_IsVAMode(SiS_Pr,HwInfo)) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->ChipType >= SIS_315H) { + if(!SiS_Pr->SiS_ROMNew) { + if(SiS_IsVAMode(SiS_Pr)) { SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); } else { SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0xFE); @@ -3803,8 +3647,8 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) { SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); } - } else if((HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730)) { + } else if((SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730)) { SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg); } } @@ -3812,25 +3656,27 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, /* SetPitch: Adapt to virtual size & position */ SiS_SetPitchCRT2(SiS_Pr, pScrn); + SiS_Handle760(SiS_Pr); + return TRUE; } /*********************************************/ -/* XFree86: SiSBIOSSetModeCRT1() */ +/* X.org/XFree86: SiSBIOSSetModeCRT1() */ /* for Dual-Head modes */ /*********************************************/ BOOLEAN -SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, +SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom) { + SISIOADDRESS BaseAddr = SiS_Pr->IOAddress; SISPtr pSiS = SISPTR(pScrn); - SISIOADDRESS BaseAddr = HwInfo->ulIOAddress; - USHORT ModeIdIndex, ModeNo=0; - UCHAR backupreg=0; + unsigned short ModeIdIndex, ModeNo = 0; + unsigned char backupreg = 0; #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; - UCHAR backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0; + unsigned char backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0; BOOLEAN backupcustom; #endif @@ -3838,43 +3684,41 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) { - USHORT temptemp = SiS_Pr->CVDisplay; + unsigned short temptemp = SiS_Pr->CVDisplay; - if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1; - else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1; + if(SiS_Pr->CModeFlag & DoubleScanMode) temptemp >>= 1; + else if(SiS_Pr->CInfoFlag & InterlaceMode) temptemp <<= 1; - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting custom mode %dx%d on CRT1\n", SiS_Pr->CHDisplay, temptemp); ModeNo = 0xfe; } else { - ModeNo = SiS_GetModeNumber(pScrn, mode, 0); - if(!ModeNo) return FALSE; + ModeNo = SiS_GetModeNumber(pScrn, mode, 0); /* don't give VBFlags */ + if(!ModeNo) return FALSE; - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x on CRT1\n", ModeNo); } - SiSInitPtr(SiS_Pr, HwInfo); + SiSInitPtr(SiS_Pr); SiSRegInit(SiS_Pr, BaseAddr); - SiS_GetSysFlags(SiS_Pr, HwInfo); -#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__)) + SiS_GetSysFlags(SiS_Pr); +#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__) || defined(__amd64__) || defined(__x86_64__) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); #else SiS_Pr->SiS_VGAINFO = 0x11; #endif - SiSInitPCIetc(SiS_Pr, HwInfo); - SiSSetLVDSetc(SiS_Pr, HwInfo); - SiSDetermineROMUsage(SiS_Pr, HwInfo); - - /* We don't clear the buffer in X */ - SiS_Pr->SiS_flag_clearbuffer = 0; SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); - SiS_UnLockCRT2(SiS_Pr, HwInfo); + SiSInitPCIetc(SiS_Pr); + SiSSetLVDSetc(SiS_Pr); + SiSDetermineROMUsage(SiS_Pr); + + SiS_UnLockCRT2(SiS_Pr); if(!SiS_Pr->UseCustomMode) { if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE; @@ -3883,10 +3727,11 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, } /* Determine VBType */ - SiS_GetVBType(SiS_Pr, HwInfo); + SiS_GetVBType(SiS_Pr); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(HwInfo->jChipType >= SIS_315H) { + SiS_InitVB(SiS_Pr); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->ChipType >= SIS_315H) { backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); } else { backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); @@ -3895,25 +3740,29 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, /* Get VB information (connectors, connected devices) */ /* (We don't care if the current mode is a CRT2 mode) */ - SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, 0); - SiS_SetYPbPr(SiS_Pr, HwInfo); - SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); - SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); - SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo); + SiS_GetVBInfo(SiS_Pr, ModeNo, ModeIdIndex, 0); + SiS_SetYPbPr(SiS_Pr); + SiS_SetTVMode(SiS_Pr, ModeNo, ModeIdIndex); + SiS_GetLCDResInfo(SiS_Pr, ModeNo, ModeIdIndex); + SiS_SetLowModeTest(SiS_Pr, ModeNo); - if(HwInfo->jChipType >= SIS_315H) { - SiS_SetupCR5x(SiS_Pr, HwInfo); - } + SiS_OpenCRTC(SiS_Pr); /* Set mode on CRT1 */ - SiS_SetCRT1Group(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); + SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex); if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - SiS_SetCRT2Group(SiS_Pr, HwInfo, ModeNo); + SiS_SetCRT2Group(SiS_Pr, ModeNo); } /* SetPitch: Adapt to virtual size & position */ SiS_SetPitchCRT1(SiS_Pr, pScrn); + SiS_HandleCRT1(SiS_Pr); + + SiS_StrangeStuff(SiS_Pr); + + SiS_CloseCRTC(SiS_Pr); + #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { pSiSEnt->CRT1ModeNo = ModeNo; @@ -3933,7 +3782,7 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { if(pSiSEnt->CRT2ModeNo != -1) { - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "(Re-)Setting mode for CRT2\n"); backupcustom = SiS_Pr->UseCustomMode; backupcr30 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); @@ -3952,9 +3801,11 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,pSiSEnt->CRT2CR35); SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,pSiSEnt->CRT2CR38); } - SiSBIOSSetModeCRT2(SiS_Pr, HwInfo, pSiSEnt->pScrn_1, + + SiSBIOSSetModeCRT2(SiS_Pr, pSiSEnt->pScrn_1, pSiSEnt->CRT2DMode, pSiSEnt->CRT2IsCustom); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,backupcr30); + + SiS_SetReg(SiS_Pr->SiS_P3d4,0x30,backupcr30); SiS_SetReg(SiS_Pr->SiS_P3d4,0x31,backupcr31); SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupcr35); SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupcr38); @@ -3970,22 +3821,20 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, * possibly overwritten */ - SiS_HandleCRT1(SiS_Pr); - - SiS_StrangeStuff(SiS_Pr, HwInfo); - SiS_DisplayOn(SiS_Pr); SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xFF); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->ChipType >= SIS_315H) { SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg); - } else if((HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730)) { + } else if((SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730)) { SiS_SetReg(SiS_Pr->SiS_P3d4,0x35,backupreg); } } + SiS_Handle760(SiS_Pr); + /* Backup/Set ModeNo in BIOS scratch area */ SiS_GetSetModeID(pScrn,ModeNo); @@ -3993,84 +3842,6 @@ SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, } #endif /* Linux_XF86 */ - -#ifdef LINUX_XF86 -BOOLEAN -SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) -{ - const USHORT PanelTypeTable300[16] = { - 0xc101, 0xc117, 0x0121, 0xc135, 0xc142, 0xc152, 0xc162, 0xc072, - 0xc181, 0xc192, 0xc1a1, 0xc1b6, 0xc1c2, 0xc0d2, 0xc1e2, 0xc1f2 - }; - const USHORT PanelTypeTable31030x[16] = { - 0xc102, 0xc112, 0x0122, 0xc132, 0xc142, 0xc152, 0xc169, 0xc179, - 0x0189, 0xc192, 0xc1a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 - }; - const USHORT PanelTypeTable310LVDS[16] = { - 0xc111, 0xc122, 0xc133, 0xc144, 0xc155, 0xc166, 0xc177, 0xc188, - 0xc199, 0xc0aa, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 - }; - USHORT tempax,tempbx,temp; - - if(HwInfo->jChipType < SIS_315H) { - - tempax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18); - tempbx = tempax & 0x0F; - if(!(tempax & 0x10)){ - if(SiS_Pr->SiS_IF_DEF_LVDS == 1){ - tempbx = 0; - temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x38); - if(temp & 0x40) tempbx |= 0x08; - if(temp & 0x20) tempbx |= 0x02; - if(temp & 0x01) tempbx |= 0x01; - temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x39); - if(temp & 0x80) tempbx |= 0x04; - } else { - return 0; - } - } - tempbx = PanelTypeTable300[tempbx]; - tempbx |= LCDSync; - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,temp); - temp = (tempbx & 0xFF00) >> 8; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp); - - } else { - - if(HwInfo->jChipType >= SIS_661) return 0; - - tempax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1a); - tempax &= 0x1e; - tempax >>= 1; - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(tempax == 0) { - /* TODO: Include HUGE detection routine - (Probably not worth bothering) - */ - return 0; - } - temp = tempax & 0xff; - tempax--; - tempbx = PanelTypeTable310LVDS[tempax]; - } else { - tempbx = PanelTypeTable31030x[tempax]; - temp = tempbx & 0xff; - } - SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,temp); - tempbx = (tempbx & 0xff00) >> 8; - temp = tempbx & 0xc1; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp); - if(SiS_Pr->SiS_VBType & VB_SISVB) { - temp = tempbx & 0x04; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x39,0xfb,temp); - } - - } - return 1; -} -#endif - #ifndef GETBITSTR #define BITMASK(h,l) (((unsigned)(1U << ((h)-(l)+1))-1)<<(l)) #define GENMASK(mask) BITMASK(1?mask,0?mask) @@ -4078,26 +3849,28 @@ SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) #define GETBITSTR(val,from,to) ((GETBITS(val,from)) << (0?to)) #endif -static void -SiS_CalcCRRegisters(SiS_Private *SiS_Pr, int depth) +void +SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth) { + int x = 1; /* Fix sync */ + SiS_Pr->CCRT1CRTC[0] = ((SiS_Pr->CHTotal >> 3) - 5) & 0xff; /* CR0 */ SiS_Pr->CCRT1CRTC[1] = (SiS_Pr->CHDisplay >> 3) - 1; /* CR1 */ SiS_Pr->CCRT1CRTC[2] = (SiS_Pr->CHBlankStart >> 3) - 1; /* CR2 */ SiS_Pr->CCRT1CRTC[3] = (((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x1F) | 0x80; /* CR3 */ SiS_Pr->CCRT1CRTC[4] = (SiS_Pr->CHSyncStart >> 3) + 3; /* CR4 */ SiS_Pr->CCRT1CRTC[5] = ((((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) | /* CR5 */ - (((SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F); + (((SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F); - SiS_Pr->CCRT1CRTC[6] = (SiS_Pr->CVTotal - 2) & 0xFF; /* CR6 */ - SiS_Pr->CCRT1CRTC[7] = (((SiS_Pr->CVTotal - 2) & 0x100) >> 8) /* CR7 */ - | (((SiS_Pr->CVDisplay - 1) & 0x100) >> 7) - | ((SiS_Pr->CVSyncStart & 0x100) >> 6) - | (((SiS_Pr->CVBlankStart - 1) & 0x100) >> 5) + SiS_Pr->CCRT1CRTC[6] = (SiS_Pr->CVTotal - 2) & 0xFF; /* CR6 */ + SiS_Pr->CCRT1CRTC[7] = (((SiS_Pr->CVTotal - 2) & 0x100) >> 8) /* CR7 */ + | (((SiS_Pr->CVDisplay - 1) & 0x100) >> 7) + | (((SiS_Pr->CVSyncStart - x) & 0x100) >> 6) + | (((SiS_Pr->CVBlankStart- 1) & 0x100) >> 5) | 0x10 - | (((SiS_Pr->CVTotal - 2) & 0x200) >> 4) - | (((SiS_Pr->CVDisplay - 1) & 0x200) >> 3) - | ((SiS_Pr->CVSyncStart & 0x200) >> 2); + | (((SiS_Pr->CVTotal - 2) & 0x200) >> 4) + | (((SiS_Pr->CVDisplay - 1) & 0x200) >> 3) + | (((SiS_Pr->CVSyncStart - x) & 0x200) >> 2); SiS_Pr->CCRT1CRTC[16] = ((((SiS_Pr->CVBlankStart - 1) & 0x200) >> 4) >> 5); /* CR9 */ @@ -4106,55 +3879,44 @@ SiS_CalcCRRegisters(SiS_Private *SiS_Pr, int depth) else if(SiS_Pr->CHDisplay >= 640) SiS_Pr->CCRT1CRTC[16] |= 0x40; } -#if 0 - if (mode->VScan >= 32) - regp->CRTC[9] |= 0x1F; - else if (mode->VScan > 1) - regp->CRTC[9] |= mode->VScan - 1; -#endif - - SiS_Pr->CCRT1CRTC[8] = (SiS_Pr->CVSyncStart ) & 0xFF; /* CR10 */ - SiS_Pr->CCRT1CRTC[9] = ((SiS_Pr->CVSyncEnd ) & 0x0F) | 0x80; /* CR11 */ + SiS_Pr->CCRT1CRTC[8] = (SiS_Pr->CVSyncStart - x) & 0xFF; /* CR10 */ + SiS_Pr->CCRT1CRTC[9] = ((SiS_Pr->CVSyncEnd - x) & 0x0F) | 0x80; /* CR11 */ SiS_Pr->CCRT1CRTC[10] = (SiS_Pr->CVDisplay - 1) & 0xFF; /* CR12 */ SiS_Pr->CCRT1CRTC[11] = (SiS_Pr->CVBlankStart - 1) & 0xFF; /* CR15 */ SiS_Pr->CCRT1CRTC[12] = (SiS_Pr->CVBlankEnd - 1) & 0xFF; /* CR16 */ SiS_Pr->CCRT1CRTC[13] = /* SRA */ - GETBITSTR((SiS_Pr->CVTotal -2), 10:10, 0:0) | - GETBITSTR((SiS_Pr->CVDisplay -1), 10:10, 1:1) | - GETBITSTR((SiS_Pr->CVBlankStart-1), 10:10, 2:2) | - GETBITSTR((SiS_Pr->CVSyncStart ), 10:10, 3:3) | - GETBITSTR((SiS_Pr->CVBlankEnd -1), 8:8, 4:4) | - GETBITSTR((SiS_Pr->CVSyncEnd ), 4:4, 5:5) ; + GETBITSTR((SiS_Pr->CVTotal -2), 10:10, 0:0) | + GETBITSTR((SiS_Pr->CVDisplay -1), 10:10, 1:1) | + GETBITSTR((SiS_Pr->CVBlankStart-1), 10:10, 2:2) | + GETBITSTR((SiS_Pr->CVSyncStart -x), 10:10, 3:3) | + GETBITSTR((SiS_Pr->CVBlankEnd -1), 8:8, 4:4) | + GETBITSTR((SiS_Pr->CVSyncEnd ), 4:4, 5:5) ; SiS_Pr->CCRT1CRTC[14] = /* SRB */ - GETBITSTR((SiS_Pr->CHTotal >> 3) - 5, 9:8, 1:0) | - GETBITSTR((SiS_Pr->CHDisplay >> 3) - 1, 9:8, 3:2) | - GETBITSTR((SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) | - GETBITSTR((SiS_Pr->CHSyncStart >> 3) + 3, 9:8, 7:6) ; + GETBITSTR((SiS_Pr->CHTotal >> 3) - 5, 9:8, 1:0) | + GETBITSTR((SiS_Pr->CHDisplay >> 3) - 1, 9:8, 3:2) | + GETBITSTR((SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) | + GETBITSTR((SiS_Pr->CHSyncStart >> 3) + 3, 9:8, 7:6) ; SiS_Pr->CCRT1CRTC[15] = /* SRC */ - GETBITSTR((SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) | - GETBITSTR((SiS_Pr->CHSyncEnd >> 3) + 3, 5:5, 2:2) ; + GETBITSTR((SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) | + GETBITSTR((SiS_Pr->CHSyncEnd >> 3) + 3, 5:5, 2:2) ; } void -SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex) +SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex) { - USHORT modeflag, tempax, tempbx, VGAHDE = SiS_Pr->SiS_VGAHDE; - int i,j; + unsigned short modeflag, tempax, tempbx = 0, remaining = 0; + unsigned short VGAHDE = SiS_Pr->SiS_VGAHDE; + int i, j; /* 1:1 data: use data set by setcrt1crtc() */ if(SiS_Pr->SiS_LCDInfo & LCDPass11) return; - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); if(modeflag & HalfDCLK) VGAHDE >>= 1; @@ -4164,32 +3926,91 @@ SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex) SiS_Pr->CVDisplay = SiS_Pr->SiS_VGAVDE; SiS_Pr->CVBlankStart = SiS_Pr->SiS_VGAVDE; - tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes; - tempax = SiS_Pr->SiS_VGAHDE; /* not /2 ! */ - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - tempax = SiS_Pr->PanelXRes; + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef SIS300 + tempbx = SiS_Pr->SiS_VGAHT; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempbx = SiS_Pr->PanelHT; + } + if(modeflag & HalfDCLK) tempbx >>= 1; + remaining = tempbx % 8; +#endif + } else { +#ifdef SIS315H + /* OK for LCDA, LVDS */ + tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes; + tempax = SiS_Pr->SiS_VGAHDE; /* not /2 ! */ + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = SiS_Pr->PanelXRes; + } + tempbx += tempax; + if(modeflag & HalfDCLK) tempbx -= VGAHDE; +#endif } - tempbx += tempax; - if(modeflag & HalfDCLK) tempbx -= VGAHDE; SiS_Pr->CHTotal = SiS_Pr->CHBlankEnd = tempbx; - tempax = VGAHDE; - tempbx = SiS_Pr->CHTotal; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - tempbx = SiS_Pr->PanelXRes; - if(modeflag & HalfDCLK) tempbx >>= 1; - tempax += ((tempbx - tempax) >> 1); + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef SIS300 + if(SiS_Pr->SiS_VGAHDE == SiS_Pr->PanelXRes) { + SiS_Pr->CHSyncStart = SiS_Pr->SiS_VGAHDE + ((SiS_Pr->PanelHRS + 1) & ~1); + SiS_Pr->CHSyncEnd = SiS_Pr->CHSyncStart + SiS_Pr->PanelHRE; + if(modeflag & HalfDCLK) { + SiS_Pr->CHSyncStart >>= 1; + SiS_Pr->CHSyncEnd >>= 1; + } + } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = (SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) >> 1; + tempbx = (SiS_Pr->PanelHRS + 1) & ~1; + if(modeflag & HalfDCLK) { + tempax >>= 1; + tempbx >>= 1; + } + SiS_Pr->CHSyncStart = (VGAHDE + tempax + tempbx + 7) & ~7; + tempax = SiS_Pr->PanelHRE + 7; + if(modeflag & HalfDCLK) tempax >>= 1; + SiS_Pr->CHSyncEnd = (SiS_Pr->CHSyncStart + tempax) & ~7; + } else { + SiS_Pr->CHSyncStart = SiS_Pr->SiS_VGAHDE; + if(modeflag & HalfDCLK) { + SiS_Pr->CHSyncStart >>= 1; + tempax = ((SiS_Pr->CHTotal - SiS_Pr->CHSyncStart) / 3) << 1; + SiS_Pr->CHSyncEnd = SiS_Pr->CHSyncStart + tempax; + } else { + SiS_Pr->CHSyncEnd = (SiS_Pr->CHSyncStart + (SiS_Pr->CHTotal / 10) + 7) & ~7; + SiS_Pr->CHSyncStart += 8; + } + } +#endif + } else { +#ifdef SIS315H + tempax = VGAHDE; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempbx = SiS_Pr->PanelXRes; + if(modeflag & HalfDCLK) tempbx >>= 1; + tempax += ((tempbx - tempax) >> 1); + } + tempax += SiS_Pr->PanelHRS; + SiS_Pr->CHSyncStart = tempax; + tempax += SiS_Pr->PanelHRE; + SiS_Pr->CHSyncEnd = tempax; +#endif } - tempax += SiS_Pr->PanelHRS; - SiS_Pr->CHSyncStart = tempax; - tempax += SiS_Pr->PanelHRE; - SiS_Pr->CHSyncEnd = tempax; - tempbx = SiS_Pr->PanelVT - SiS_Pr->PanelYRes; tempax = SiS_Pr->SiS_VGAVDE; if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { tempax = SiS_Pr->PanelYRes; + } else if(SiS_Pr->ChipType < SIS_315H) { +#ifdef SIS300 + /* Stupid hack for 640x400/320x200 */ + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if((tempax + tempbx) == 438) tempbx += 16; + } else if((SiS_Pr->SiS_LCDResInfo == Panel_800x600) || + (SiS_Pr->SiS_LCDResInfo == Panel_1024x600)) { + tempax = 0; + tempbx = SiS_Pr->SiS_VGAVT; + } +#endif } SiS_Pr->CVTotal = SiS_Pr->CVBlankEnd = tempbx + tempax; @@ -4201,22 +4022,28 @@ SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex) SiS_Pr->CVSyncStart = tempax; tempax += SiS_Pr->PanelVRE; SiS_Pr->CVSyncEnd = tempax; + if(SiS_Pr->ChipType < SIS_315H) { + SiS_Pr->CVSyncStart--; + SiS_Pr->CVSyncEnd--; + } SiS_CalcCRRegisters(SiS_Pr, 8); + SiS_Pr->CCRT1CRTC[15] &= ~0xF8; + SiS_Pr->CCRT1CRTC[15] |= (remaining << 4); SiS_Pr->CCRT1CRTC[16] &= ~0xE0; SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); - for(i=0,j=0;i<=7;i++,j++) { + for(i = 0, j = 0; i <= 7; i++, j++) { SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); } - for(j=0x10;i<=10;i++,j++) { + for(j = 0x10; i <= 10; i++, j++) { SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); } - for(j=0x15;i<=12;i++,j++) { + for(j = 0x15; i <= 12; i++, j++) { SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); } - for(j=0x0A;i<=15;i++,j++) { + for(j = 0x0A; i <= 15; i++, j++) { SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]); } @@ -4227,1092 +4054,192 @@ SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex) if(modeflag & DoubleScanMode) tempax |= 0x80; SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,tempax); +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "%d %d %d %d %d %d %d %d (%d %d %d %d)\n", - SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal, + SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal, SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal, SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd); - xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", - SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1], + SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1], SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3], SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5], SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]); xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", - SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9], + SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9], SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11], SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13], SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]); xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]); #endif +#endif } -#ifdef LINUX_XF86 - void -SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, UCHAR *p2b, UCHAR *p2c) -{ - int out_n, out_dn, out_div, out_sbit, out_scale; - unsigned int vclk[5]; - -#define Midx 0 -#define Nidx 1 -#define VLDidx 2 -#define Pidx 3 -#define PSNidx 4 - - if(SiS_compute_vclk(clock, &out_n, &out_dn, &out_div, &out_sbit, &out_scale)) { - (*p2b) = (out_div == 2) ? 0x80 : 0x00; - (*p2b) |= ((out_n - 1) & 0x7f); - (*p2c) = (out_dn - 1) & 0x1f; - (*p2c) |= (((out_scale - 1) & 3) << 5); - (*p2c) |= ((out_sbit & 0x01) << 7); -#ifdef TWDEBUG - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sb %d sc %d\n", - clock, out_n, out_dn, out_div, out_sbit, out_scale); +SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, + int xres, int yres, +#ifdef SIS_XORG_XF86 + DisplayModePtr current #endif - } else { - SiSCalcClock(pScrn, clock, 2, vclk); - (*p2b) = (vclk[VLDidx] == 2) ? 0x80 : 0x00; - (*p2b) |= (vclk[Midx] - 1) & 0x7f; - (*p2c) = (vclk[Nidx] - 1) & 0x1f; - if(vclk[Pidx] <= 4) { - /* postscale 1,2,3,4 */ - (*p2c) |= ((vclk[Pidx] - 1) & 3) << 5; - } else { - /* postscale 6,8 */ - (*p2c) |= (((vclk[Pidx] / 2) - 1) & 3) << 5; - (*p2c) |= 0x80; - } -#ifdef TWDEBUG - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clock %d: n %d dn %d div %d sc %d\n", - clock, vclk[Midx], vclk[Nidx], vclk[VLDidx], vclk[Pidx]); -#endif - } -} - +#ifdef SIS_LINUX_KERNEL + struct fb_var_screeninfo *var, BOOLEAN writeres #endif - -/* ================ XFREE86/X.ORG ================= */ - -/* Helper functions */ - -#ifdef LINUX_XF86 - -USHORT -SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags) +) { - SISPtr pSiS = SISPTR(pScrn); - int depth = pSiS->CurrentLayout.bitsPerPixel; - - pSiS->SiS_Pr->CModeFlag = 0; - - pSiS->SiS_Pr->CDClock = mode->Clock; - - pSiS->SiS_Pr->CHDisplay = mode->HDisplay; - pSiS->SiS_Pr->CHSyncStart = mode->HSyncStart; - pSiS->SiS_Pr->CHSyncEnd = mode->HSyncEnd; - pSiS->SiS_Pr->CHTotal = mode->HTotal; - - pSiS->SiS_Pr->CVDisplay = mode->VDisplay; - pSiS->SiS_Pr->CVSyncStart = mode->VSyncStart; - pSiS->SiS_Pr->CVSyncEnd = mode->VSyncEnd; - pSiS->SiS_Pr->CVTotal = mode->VTotal; - - pSiS->SiS_Pr->CFlags = mode->Flags; - - if(pSiS->SiS_Pr->CFlags & V_INTERLACE) { - pSiS->SiS_Pr->CVDisplay >>= 1; - pSiS->SiS_Pr->CVSyncStart >>= 1; - pSiS->SiS_Pr->CVSyncEnd >>= 1; - pSiS->SiS_Pr->CVTotal >>= 1; - } - if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) { - /* pSiS->SiS_Pr->CDClock <<= 1; */ - pSiS->SiS_Pr->CVDisplay <<= 1; - pSiS->SiS_Pr->CVSyncStart <<= 1; - pSiS->SiS_Pr->CVSyncEnd <<= 1; - pSiS->SiS_Pr->CVTotal <<= 1; - } + unsigned short HRE, HBE, HRS, HBS, HDE, HT; + unsigned short VRE, VBE, VRS, VBS, VDE, VT; + unsigned char sr_data, cr_data, cr_data2; + int A, B, C, D, E, F, temp; - pSiS->SiS_Pr->CHBlankStart = pSiS->SiS_Pr->CHDisplay; - pSiS->SiS_Pr->CHBlankEnd = pSiS->SiS_Pr->CHTotal; - pSiS->SiS_Pr->CVBlankStart = pSiS->SiS_Pr->CVSyncStart - 1; - pSiS->SiS_Pr->CVBlankEnd = pSiS->SiS_Pr->CVTotal; + sr_data = crdata[14]; - SiS_MakeClockRegs(pScrn, pSiS->SiS_Pr->CDClock, &pSiS->SiS_Pr->CSR2B, &pSiS->SiS_Pr->CSR2C); + /* Horizontal total */ + HT = crdata[0] | ((unsigned short)(sr_data & 0x03) << 8); + A = HT + 5; - pSiS->SiS_Pr->CSRClock = (pSiS->SiS_Pr->CDClock / 1000) + 1; + /* Horizontal display enable end */ + HDE = crdata[1] | ((unsigned short)(sr_data & 0x0C) << 6); + E = HDE + 1; - SiS_CalcCRRegisters(pSiS->SiS_Pr, depth); + /* Horizontal retrace (=sync) start */ + HRS = crdata[4] | ((unsigned short)(sr_data & 0xC0) << 2); + F = HRS - E - 3; - switch(depth) { - case 8: pSiS->SiS_Pr->CModeFlag |= 0x223b; break; - case 16: pSiS->SiS_Pr->CModeFlag |= 0x227d; break; - case 32: pSiS->SiS_Pr->CModeFlag |= 0x22ff; break; - default: return 0; - } + /* Horizontal blank start */ + HBS = crdata[2] | ((unsigned short)(sr_data & 0x30) << 4); - if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) - pSiS->SiS_Pr->CModeFlag |= DoubleScanMode; + sr_data = crdata[15]; + cr_data = crdata[5]; - if((pSiS->SiS_Pr->CVDisplay >= 1024) || - (pSiS->SiS_Pr->CVTotal >= 1024) || - (pSiS->SiS_Pr->CHDisplay >= 1024)) - pSiS->SiS_Pr->CModeFlag |= LineCompareOff; + /* Horizontal blank end */ + HBE = (crdata[3] & 0x1f) | + ((unsigned short)(cr_data & 0x80) >> 2) | + ((unsigned short)(sr_data & 0x03) << 6); - if(pSiS->SiS_Pr->CFlags & V_CLKDIV2) - pSiS->SiS_Pr->CModeFlag |= HalfDCLK; + /* Horizontal retrace (=sync) end */ + HRE = (cr_data & 0x1f) | ((sr_data & 0x04) << 3); - pSiS->SiS_Pr->CInfoFlag = 0x0007; + temp = HBE - ((E - 1) & 255); + B = (temp > 0) ? temp : (temp + 256); - if(pSiS->SiS_Pr->CFlags & V_NHSYNC) - pSiS->SiS_Pr->CInfoFlag |= 0x4000; + temp = HRE - ((E + F + 3) & 63); + C = (temp > 0) ? temp : (temp + 64); - if(pSiS->SiS_Pr->CFlags & V_NVSYNC) - pSiS->SiS_Pr->CInfoFlag |= 0x8000; + D = B - F - C; - if(pSiS->SiS_Pr->CFlags & V_INTERLACE) - pSiS->SiS_Pr->CInfoFlag |= InterlaceMode; - - pSiS->SiS_Pr->UseCustomMode = TRUE; +#ifdef SIS_XORG_XF86 + current->HDisplay = (E * 8); + current->HSyncStart = (E * 8) + (F * 8); + current->HSyncEnd = (E * 8) + (F * 8) + (C * 8); + current->HTotal = (E * 8) + (F * 8) + (C * 8) + (D * 8); #ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "Custom mode %dx%d:\n", - pSiS->SiS_Pr->CHDisplay,pSiS->SiS_Pr->CVDisplay); - xf86DrvMsg(0, X_INFO, "Modeflag %04x, Infoflag %04x\n", - pSiS->SiS_Pr->CModeFlag, pSiS->SiS_Pr->CInfoFlag); - xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", - pSiS->SiS_Pr->CCRT1CRTC[0], pSiS->SiS_Pr->CCRT1CRTC[1], - pSiS->SiS_Pr->CCRT1CRTC[2], pSiS->SiS_Pr->CCRT1CRTC[3], - pSiS->SiS_Pr->CCRT1CRTC[4], pSiS->SiS_Pr->CCRT1CRTC[5], - pSiS->SiS_Pr->CCRT1CRTC[6], pSiS->SiS_Pr->CCRT1CRTC[7]); - xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", - pSiS->SiS_Pr->CCRT1CRTC[8], pSiS->SiS_Pr->CCRT1CRTC[9], - pSiS->SiS_Pr->CCRT1CRTC[10], pSiS->SiS_Pr->CCRT1CRTC[11], - pSiS->SiS_Pr->CCRT1CRTC[12], pSiS->SiS_Pr->CCRT1CRTC[13], - pSiS->SiS_Pr->CCRT1CRTC[14], pSiS->SiS_Pr->CCRT1CRTC[15]); - xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", pSiS->SiS_Pr->CCRT1CRTC[16]); - xf86DrvMsg(0, X_INFO, "Clock: 0x%02x, 0x%02x, %d\n", - pSiS->SiS_Pr->CSR2B, pSiS->SiS_Pr->CSR2C, pSiS->SiS_Pr->CSRClock); -#endif - return 1; -} - -int -SiS_FindPanelFromDB(SISPtr pSiS, USHORT panelvendor, USHORT panelproduct, int *maxx, int *maxy, int *prefx, int *prefy) -{ - int i, j; - BOOLEAN done = FALSE; - - i = 0; - while((!done) && (SiS_PlasmaTable[i].vendor) && panelvendor) { - if(SiS_PlasmaTable[i].vendor == panelvendor) { - for(j=0; j<SiS_PlasmaTable[i].productnum; j++) { - if(SiS_PlasmaTable[i].product[j] == panelproduct) { - if(SiS_PlasmaTable[i].maxx && SiS_PlasmaTable[i].maxy) { - (*maxx) = (int)SiS_PlasmaTable[i].maxx; - (*maxy) = (int)SiS_PlasmaTable[i].maxy; - (*prefx) = (int)SiS_PlasmaTable[i].prefx; - (*prefy) = (int)SiS_PlasmaTable[i].prefy; - done = TRUE; - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "Identified %s, correcting max X res %d, max Y res %d\n", - SiS_PlasmaTable[i].plasmaname, - SiS_PlasmaTable[i].maxx, SiS_PlasmaTable[i].maxy); - break; - } - } - } - } - i++; - } - return (done) ? 1 : 0; -} - -/* Build a list of supported modes: - * Built-in modes for which we have all data are M_T_DEFAULT, - * modes derived from DDC or database data are M_T_BUILTIN - */ -DisplayModePtr -SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi) -{ - SISPtr pSiS = SISPTR(pScrn); - unsigned short VRE, VBE, VRS, VBS, VDE, VT; - unsigned short HRE, HBE, HRS, HBS, HDE, HT; - unsigned char sr_data, cr_data, cr_data2, cr_data3; - unsigned char sr2b, sr2c; - float num, denum, postscalar, divider; - int A, B, C, D, E, F, temp, i, j, k, l, index, vclkindex; - DisplayModePtr new = NULL, current = NULL, first = NULL; - BOOLEAN done = FALSE; -#if 0 - DisplayModePtr backup = NULL; -#endif - - pSiS->backupmodelist = NULL; - pSiS->AddedPlasmaModes = FALSE; - - /* Initialize our pointers */ - if(pSiS->VGAEngine == SIS_300_VGA) { -#ifdef SIS300 - InitTo300Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext); + xf86DrvMsg(0, X_INFO, + "H: A %d B %d C %d D %d E %d F %d HT %d HDE %d HRS %d HBS %d HBE %d HRE %d\n", + A, B, C, D, E, F, HT, HDE, HRS, HBS, HBE, HRE); #else - return NULL; + (void)VBS; (void)HBS; (void)A; #endif - } else if(pSiS->VGAEngine == SIS_315_VGA) { -#ifdef SIS315H - InitTo310Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext); -#else - return NULL; #endif - } else return NULL; - - i = 0; - while(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag != 0xFFFF) { - - index = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRT1CRTC; - - /* 0x5a (320x240) is a pure FTSN mode, not DSTN! */ - if((!pSiS->FSTN) && - (pSiS->SiS_Pr->SiS_RefIndex[i].ModeID == 0x5a)) { - i++; - continue; - } - if((pSiS->FSTN) && - (pSiS->SiS_Pr->SiS_RefIndex[i].XRes == 320) && - (pSiS->SiS_Pr->SiS_RefIndex[i].YRes == 240) && - (pSiS->SiS_Pr->SiS_RefIndex[i].ModeID != 0x5a)) { - i++; - continue; - } - - if(!(new = xalloc(sizeof(DisplayModeRec)))) return first; - memset(new, 0, sizeof(DisplayModeRec)); - if(!(new->name = xalloc(10))) { - xfree(new); - return first; - } - if(!first) first = new; - if(current) { - current->next = new; - new->prev = current; - } - - current = new; - - sprintf(current->name, "%dx%d", pSiS->SiS_Pr->SiS_RefIndex[i].XRes, - pSiS->SiS_Pr->SiS_RefIndex[i].YRes); - - current->status = MODE_OK; - - current->type = M_T_DEFAULT; - - vclkindex = pSiS->SiS_Pr->SiS_RefIndex[i].Ext_CRTVCLK; - if(pSiS->VGAEngine == SIS_300_VGA) vclkindex &= 0x3F; - - sr2b = pSiS->SiS_Pr->SiS_VCLKData[vclkindex].SR2B; - sr2c = pSiS->SiS_Pr->SiS_VCLKData[vclkindex].SR2C; - - divider = (sr2b & 0x80) ? 2.0 : 1.0; - postscalar = (sr2c & 0x80) ? - ( (((sr2c >> 5) & 0x03) == 0x02) ? 6.0 : 8.0) : (((sr2c >> 5) & 0x03) + 1.0); - num = (sr2b & 0x7f) + 1.0; - denum = (sr2c & 0x1f) + 1.0; - -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "------------\n"); - xf86DrvMsg(0, X_INFO, "sr2b: %x sr2c %x div %f ps %f num %f denum %f\n", - sr2b, sr2c, divider, postscalar, num, denum); +#ifdef SIS_LINUX_KERNEL + if(writeres) var->xres = xres = E * 8; + var->left_margin = D * 8; + var->right_margin = F * 8; + var->hsync_len = C * 8; #endif - current->Clock = (int)(14318 * (divider / postscalar) * (num / denum)); - - sr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[14]; - /* inSISIDXREG(SISSR, 0x0b, sr_data); */ - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[0]; - /* inSISIDXREG(SISCR, 0x00, cr_data); */ - - /* Horizontal total */ - HT = (cr_data & 0xff) | - ((unsigned short) (sr_data & 0x03) << 8); - A = HT + 5; - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[1]; - /* inSISIDXREG(SISCR, 0x01, cr_data); */ - - /* Horizontal display enable end */ - HDE = (cr_data & 0xff) | - ((unsigned short) (sr_data & 0x0C) << 6); - E = HDE + 1; /* 0x80 0x64 */ - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[4]; - /* inSISIDXREG(SISCR, 0x04, cr_data); */ - - /* Horizontal retrace (=sync) start */ - HRS = (cr_data & 0xff) | - ((unsigned short) (sr_data & 0xC0) << 2); - F = HRS - E - 3; /* 0x06 0x06 */ - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[2]; - /* inSISIDXREG(SISCR, 0x02, cr_data); */ - - /* Horizontal blank start */ - HBS = (cr_data & 0xff) | - ((unsigned short) (sr_data & 0x30) << 4); - - sr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[15]; - /* inSISIDXREG(SISSR, 0x0c, sr_data); */ - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[3]; - /* inSISIDXREG(SISCR, 0x03, cr_data); */ - - cr_data2 = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[5]; - /* inSISIDXREG(SISCR, 0x05, cr_data2); */ - - /* Horizontal blank end */ - HBE = (cr_data & 0x1f) | - ((unsigned short) (cr_data2 & 0x80) >> 2) | - ((unsigned short) (sr_data & 0x03) << 6); - - /* Horizontal retrace (=sync) end */ - HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3); - - temp = HBE - ((E - 1) & 255); - B = (temp > 0) ? temp : (temp + 256); - - temp = HRE - ((E + F + 3) & 63); - C = (temp > 0) ? temp : (temp + 64); /* 0x0b 0x0b */ - - D = B - F - C; - - if((pSiS->SiS_Pr->SiS_RefIndex[i].XRes == 320) && - ((pSiS->SiS_Pr->SiS_RefIndex[i].YRes == 200) || - (pSiS->SiS_Pr->SiS_RefIndex[i].YRes == 240))) { - - /* Terrible hack, but correct CRTC data for - * these modes only produces a black screen... - * (HRE is 0, leading into a too large C and - * a negative D. The CRT controller does not - * seem to like correcting HRE to 50 - */ - current->HDisplay = 320; - current->HSyncStart = 328; - current->HSyncEnd = 376; - current->HTotal = 400; - - } else { - - current->HDisplay = (E * 8); - current->HSyncStart = (E * 8) + (F * 8); - current->HSyncEnd = (E * 8) + (F * 8) + (C * 8); - current->HTotal = (E * 8) + (F * 8) + (C * 8) + (D * 8); - - } - -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, - "H: A %d B %d C %d D %d E %d F %d HT %d HDE %d HRS %d HBS %d HBE %d HRE %d\n", - A, B, C, D, E, F, HT, HDE, HRS, HBS, HBE, HRE); -#endif - - sr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[13]; - /* inSISIDXREG(SISSR, 0x0A, sr_data); */ - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[6]; - /* inSISIDXREG(SISCR, 0x06, cr_data); */ - - cr_data2 = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[7]; - /* inSISIDXREG(SISCR, 0x07, cr_data2); */ - - /* Vertical total */ - VT = (cr_data & 0xFF) | - ((unsigned short) (cr_data2 & 0x01) << 8) | - ((unsigned short)(cr_data2 & 0x20) << 4) | - ((unsigned short) (sr_data & 0x01) << 10); - A = VT + 2; - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[10]; - /* inSISIDXREG(SISCR, 0x12, cr_data); */ - - /* Vertical display enable end */ - VDE = (cr_data & 0xff) | - ((unsigned short) (cr_data2 & 0x02) << 7) | - ((unsigned short) (cr_data2 & 0x40) << 3) | - ((unsigned short) (sr_data & 0x02) << 9); - E = VDE + 1; - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[8]; - /* inSISIDXREG(SISCR, 0x10, cr_data); */ - - /* Vertical retrace (=sync) start */ - VRS = (cr_data & 0xff) | - ((unsigned short) (cr_data2 & 0x04) << 6) | - ((unsigned short) (cr_data2 & 0x80) << 2) | - ((unsigned short) (sr_data & 0x08) << 7); - F = VRS + 1 - E; - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[11]; - /* inSISIDXREG(SISCR, 0x15, cr_data); */ - - cr_data3 = (pSiS->SiS_Pr->SiS_CRT1Table[index].CR[16] & 0x01) << 5; - /* inSISIDXREG(SISCR, 0x09, cr_data3); */ - - /* Vertical blank start */ - VBS = (cr_data & 0xff) | - ((unsigned short) (cr_data2 & 0x08) << 5) | - ((unsigned short) (cr_data3 & 0x20) << 4) | - ((unsigned short) (sr_data & 0x04) << 8); - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[12]; - /* inSISIDXREG(SISCR, 0x16, cr_data); */ - - /* Vertical blank end */ - VBE = (cr_data & 0xff) | - ((unsigned short) (sr_data & 0x10) << 4); - temp = VBE - ((E - 1) & 511); - B = (temp > 0) ? temp : (temp + 512); - - cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[9]; - /* inSISIDXREG(SISCR, 0x11, cr_data); */ - - /* Vertical retrace (=sync) end */ - VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); - temp = VRE - ((E + F - 1) & 31); - C = (temp > 0) ? temp : (temp + 32); - - D = B - F - C; - - current->VDisplay = VDE + 1; - current->VSyncStart = VRS + 1; - current->VSyncEnd = ((VRS & ~0x1f) | VRE) + 1; - if(VRE <= (VRS & 0x1f)) current->VSyncEnd += 32; - current->VTotal = E + D + C + F; - + /* Vertical */ + sr_data = crdata[13]; + cr_data = crdata[7]; + + /* Vertical total */ + VT = crdata[6] | + ((unsigned short)(cr_data & 0x01) << 8) | + ((unsigned short)(cr_data & 0x20) << 4) | + ((unsigned short)(sr_data & 0x01) << 10); + A = VT + 2; + + /* Vertical display enable end */ + VDE = crdata[10] | + ((unsigned short)(cr_data & 0x02) << 7) | + ((unsigned short)(cr_data & 0x40) << 3) | + ((unsigned short)(sr_data & 0x02) << 9); + E = VDE + 1; + + /* Vertical retrace (=sync) start */ + VRS = crdata[8] | + ((unsigned short)(cr_data & 0x04) << 6) | + ((unsigned short)(cr_data & 0x80) << 2) | + ((unsigned short)(sr_data & 0x08) << 7); + F = VRS + 1 - E; + + cr_data2 = (crdata[16] & 0x01) << 5; + + /* Vertical blank start */ + VBS = crdata[11] | + ((unsigned short)(cr_data & 0x08) << 5) | + ((unsigned short)(cr_data2 & 0x20) << 4) | + ((unsigned short)(sr_data & 0x04) << 8); + + /* Vertical blank end */ + VBE = crdata[12] | ((unsigned short)(sr_data & 0x10) << 4); + temp = VBE - ((E - 1) & 511); + B = (temp > 0) ? temp : (temp + 512); + + /* Vertical retrace (=sync) end */ + VRE = (crdata[9] & 0x0f) | ((sr_data & 0x20) >> 1); + temp = VRE - ((E + F - 1) & 31); + C = (temp > 0) ? temp : (temp + 32); + + D = B - F - C; + +#ifdef SIS_XORG_XF86 + current->VDisplay = VDE + 1; + current->VSyncStart = VRS + 1; + current->VSyncEnd = ((VRS & ~0x1f) | VRE) + 1; + if(VRE <= (VRS & 0x1f)) current->VSyncEnd += 32; + current->VTotal = E + D + C + F; #if 0 - current->VDisplay = E; - current->VSyncStart = E + D; - current->VSyncEnd = E + D + C; - current->VTotal = E + D + C + F; + current->VDisplay = E; + current->VSyncStart = E + D; + current->VSyncEnd = E + D + C; + current->VTotal = E + D + C + F; #endif - -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, - "V: A %d B %d C %d D %d E %d F %d VT %d VDE %d VRS %d VBS %d VBE %d VRE %d\n", - A, B, C, D, E, F, VT, VDE, VRS, VBS, VBE, VRE); -#endif - - if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x4000) - current->Flags |= V_NHSYNC; - else - current->Flags |= V_PHSYNC; - - if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x8000) - current->Flags |= V_NVSYNC; - else - current->Flags |= V_PVSYNC; - - if(pSiS->SiS_Pr->SiS_RefIndex[i].Ext_InfoFlag & 0x0080) - current->Flags |= V_INTERLACE; - - j = 0; - while(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) { - if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID == - pSiS->SiS_Pr->SiS_RefIndex[i].ModeID) { - if(pSiS->SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) { - current->Flags |= V_DBLSCAN; - } - break; - } - j++; - } - - if(current->Flags & V_INTERLACE) { - current->VDisplay <<= 1; - current->VSyncStart <<= 1; - current->VSyncEnd <<= 1; - current->VTotal <<= 1; - current->VTotal |= 1; - } - if(current->Flags & V_DBLSCAN) { - current->Clock >>= 1; - current->VDisplay >>= 1; - current->VSyncStart >>= 1; - current->VSyncEnd >>= 1; - current->VTotal >>= 1; - } - #ifdef TWDEBUG - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Built-in: %s %.2f %d %d %d %d %d %d %d %d\n", - current->name, (float)current->Clock / 1000, - current->HDisplay, current->HSyncStart, current->HSyncEnd, current->HTotal, - current->VDisplay, current->VSyncStart, current->VSyncEnd, current->VTotal); -#else - (void)VBS; (void)HBS; (void)A; + xf86DrvMsg(0, X_INFO, + "V: A %d B %d C %d D %d E %d F %d VT %d VDE %d VRS %d VBS %d VBE %d VRE %d\n", + A, B, C, D, E, F, VT, VDE, VRS, VBS, VBE, VRE); #endif - - i++; - } - - /* Add non-standard LCD modes for panel's detailed timings */ - - if(!includelcdmodes) return first; - - if(pSiS->SiS_Pr->CP_Vendor) { - xf86DrvMsg(0, X_INFO, "Checking database for vendor %x, product %x\n", - pSiS->SiS_Pr->CP_Vendor, pSiS->SiS_Pr->CP_Product); - } - - i = 0; - while((!done) && (SiS_PlasmaTable[i].vendor) && (pSiS->SiS_Pr->CP_Vendor)) { - - if(SiS_PlasmaTable[i].vendor == pSiS->SiS_Pr->CP_Vendor) { - - for(j=0; j<SiS_PlasmaTable[i].productnum; j++) { - - if(SiS_PlasmaTable[i].product[j] == pSiS->SiS_Pr->CP_Product) { - - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, - "Identified %s panel, adding specific modes\n", - SiS_PlasmaTable[i].plasmaname); - - for(k=0; k<SiS_PlasmaTable[i].modenum; k++) { - - if(isfordvi) { - if(!(SiS_PlasmaTable[i].plasmamodes[k] & 0x80)) continue; - } else { - if(!(SiS_PlasmaTable[i].plasmamodes[k] & 0x40)) continue; - } - - l = SiS_PlasmaTable[i].plasmamodes[k] & 0x3f; - - if(pSiS->VBFlags & (VB_301|VB_301B|VB_302B|VB_301LV)) { - if(isfordvi) { - if(SiS_PlasmaMode[l].VDisplay > 1024) continue; - } - } - - if(!(new = xalloc(sizeof(DisplayModeRec)))) return first; - - memset(new, 0, sizeof(DisplayModeRec)); - if(!(new->name = xalloc(12))) { - xfree(new); - return first; - } - if(!first) first = new; - if(current) { - current->next = new; - new->prev = current; - } - - current = new; - - pSiS->AddedPlasmaModes = TRUE; - - strcpy(current->name, SiS_PlasmaMode[l].name); - /* sprintf(current->name, "%dx%d", SiS_PlasmaMode[l].HDisplay, - SiS_PlasmaMode[l].VDisplay); */ - - current->status = MODE_OK; - - current->type = M_T_BUILTIN; - - current->Clock = SiS_PlasmaMode[l].clock; - current->SynthClock = current->Clock; - - current->HDisplay = SiS_PlasmaMode[l].HDisplay; - current->HSyncStart = current->HDisplay + SiS_PlasmaMode[l].HFrontPorch; - current->HSyncEnd = current->HSyncStart + SiS_PlasmaMode[l].HSyncWidth; - current->HTotal = SiS_PlasmaMode[l].HTotal; - - current->VDisplay = SiS_PlasmaMode[l].VDisplay; - current->VSyncStart = current->VDisplay + SiS_PlasmaMode[l].VFrontPorch; - current->VSyncEnd = current->VSyncStart + SiS_PlasmaMode[l].VSyncWidth; - current->VTotal = SiS_PlasmaMode[l].VTotal; - - current->CrtcHDisplay = current->HDisplay; - current->CrtcHBlankStart = current->HSyncStart; - current->CrtcHSyncStart = current->HSyncStart; - current->CrtcHSyncEnd = current->HSyncEnd; - current->CrtcHBlankEnd = current->HSyncEnd; - current->CrtcHTotal = current->HTotal; - - current->CrtcVDisplay = current->VDisplay; - current->CrtcVBlankStart = current->VSyncStart; - current->CrtcVSyncStart = current->VSyncStart; - current->CrtcVSyncEnd = current->VSyncEnd; - current->CrtcVBlankEnd = current->VSyncEnd; - current->CrtcVTotal = current->VTotal; - - if(SiS_PlasmaMode[l].SyncFlags & SIS_PL_HSYNCP) - current->Flags |= V_PHSYNC; - else - current->Flags |= V_NHSYNC; - - if(SiS_PlasmaMode[l].SyncFlags & SIS_PL_VSYNCP) - current->Flags |= V_PVSYNC; - else - current->Flags |= V_NVSYNC; - - if(current->HDisplay > pSiS->LCDwidth) - pSiS->LCDwidth = pSiS->SiS_Pr->CP_MaxX = current->HDisplay; - if(current->VDisplay > pSiS->LCDheight) - pSiS->LCDheight = pSiS->SiS_Pr->CP_MaxY = current->VDisplay; - - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, - "\tAdding \"%s\" to list of built-in modes\n", current->name); - - } - done = TRUE; - break; - } - } - } - - i++; - - } - - if(pSiS->SiS_Pr->CP_HaveCustomData) { - - for(i=0; i<7; i++) { - - if(pSiS->SiS_Pr->CP_DataValid[i]) { - - if(!(new = xalloc(sizeof(DisplayModeRec)))) return first; - - memset(new, 0, sizeof(DisplayModeRec)); - if(!(new->name = xalloc(10))) { - xfree(new); - return first; - } - if(!first) first = new; - if(current) { - current->next = new; - new->prev = current; - } - - current = new; - - sprintf(current->name, "%dx%d", pSiS->SiS_Pr->CP_HDisplay[i], - pSiS->SiS_Pr->CP_VDisplay[i]); - - current->status = MODE_OK; - - current->type = M_T_BUILTIN; - - current->Clock = pSiS->SiS_Pr->CP_Clock[i]; - current->SynthClock = current->Clock; - - current->HDisplay = pSiS->SiS_Pr->CP_HDisplay[i]; - current->HSyncStart = pSiS->SiS_Pr->CP_HSyncStart[i]; - current->HSyncEnd = pSiS->SiS_Pr->CP_HSyncEnd[i]; - current->HTotal = pSiS->SiS_Pr->CP_HTotal[i]; - - current->VDisplay = pSiS->SiS_Pr->CP_VDisplay[i]; - current->VSyncStart = pSiS->SiS_Pr->CP_VSyncStart[i]; - current->VSyncEnd = pSiS->SiS_Pr->CP_VSyncEnd[i]; - current->VTotal = pSiS->SiS_Pr->CP_VTotal[i]; - - current->CrtcHDisplay = current->HDisplay; - current->CrtcHBlankStart = pSiS->SiS_Pr->CP_HBlankStart[i]; - current->CrtcHSyncStart = current->HSyncStart; - current->CrtcHSyncEnd = current->HSyncEnd; - current->CrtcHBlankEnd = pSiS->SiS_Pr->CP_HBlankEnd[i]; - current->CrtcHTotal = current->HTotal; - - current->CrtcVDisplay = current->VDisplay; - current->CrtcVBlankStart = pSiS->SiS_Pr->CP_VBlankStart[i]; - current->CrtcVSyncStart = current->VSyncStart; - current->CrtcVSyncEnd = current->VSyncEnd; - current->CrtcVBlankEnd = pSiS->SiS_Pr->CP_VBlankEnd[i]; - current->CrtcVTotal = current->VTotal; - - if(pSiS->SiS_Pr->CP_SyncValid[i]) { - if(pSiS->SiS_Pr->CP_HSync_P[i]) - current->Flags |= V_PHSYNC; - else - current->Flags |= V_NHSYNC; - - if(pSiS->SiS_Pr->CP_VSync_P[i]) - current->Flags |= V_PVSYNC; - else - current->Flags |= V_NVSYNC; - } else { - /* No sync data? Use positive sync... */ - current->Flags |= V_PHSYNC; - current->Flags |= V_PVSYNC; - } - } - } - } - - return first; - -} - -/* Translate a mode number into the VESA pendant */ -int -SiSTranslateToVESA(ScrnInfoPtr pScrn, int modenumber) -{ - SISPtr pSiS = SISPTR(pScrn); - int i = 0; - - /* Initialize our pointers */ - if(pSiS->VGAEngine == SIS_300_VGA) { -#ifdef SIS300 - InitTo300Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext); -#else - return -1; #endif - } else if(pSiS->VGAEngine == SIS_315_VGA) { -#ifdef SIS315H - InitTo310Pointer(pSiS->SiS_Pr, &pSiS->sishw_ext); -#else - return -1; +#ifdef SIS_LINUX_KERNEL + if(writeres) var->yres = yres = E; + var->upper_margin = D; + var->lower_margin = F; + var->vsync_len = C; #endif - } else return -1; - - if(modenumber <= 0x13) return modenumber; -#ifdef SIS315H - if(pSiS->ROM661New) { - while(SiS_EModeIDTable661[i].Ext_ModeID != 0xff) { - if(SiS_EModeIDTable661[i].Ext_ModeID == modenumber) { - return (int)SiS_EModeIDTable661[i].Ext_VESAID; - } - i++; - } - } else { + if((xres == 320) && ((yres == 200) || (yres == 240))) { + /* Terrible hack, but correct CRTC data for + * these modes only produces a black screen... + * (HRE is 0, leading into a too large C and + * a negative D. The CRT controller does not + * seem to like correcting HRE to 50) + */ +#ifdef SIS_XORG_XF86 + current->HDisplay = 320; + current->HSyncStart = 328; + current->HSyncEnd = 376; + current->HTotal = 400; #endif - while(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID != 0xff) { - if(pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID == modenumber) { - return (int)pSiS->SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID; - } - i++; - } -#ifdef SIS315H - } +#ifdef SIS_LINUX_KERNEL + var->left_margin = (400 - 376); + var->right_margin = (328 - 320); + var->hsync_len = (376 - 328); #endif - return -1; -} -/* Translate a new BIOS mode number into the driver's pendant */ -int -SiSTranslateToOldMode(int modenumber) -{ -#ifdef SIS315H - int i = 0; - - while(SiS_EModeIDTable661[i].Ext_ModeID != 0xff) { - if(SiS_EModeIDTable661[i].Ext_ModeID == modenumber) { - if(SiS_EModeIDTable661[i].Ext_MyModeID) - return (int)SiS_EModeIDTable661[i].Ext_MyModeID; - else - return modenumber; - } - i++; } -#endif - return modenumber; -} - -#endif /* Xfree86 */ -#ifdef LINUX_KERNEL -int -sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - unsigned char modeno, unsigned char rateindex) -{ - USHORT ModeNo = modeno; - USHORT ModeIdIndex = 0, ClockIndex = 0; - USHORT RefreshRateTableIndex = 0; - int Clock; - - if(HwInfo->jChipType < SIS_315H) { -#ifdef SIS300 - InitTo300Pointer(SiS_Pr, HwInfo); -#else - return 65 * 1000; -#endif - } else { -#ifdef SIS315H - InitTo310Pointer(SiS_Pr, HwInfo); -#else - return 65 * 1000; -#endif - } - - if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {; - printk(KERN_ERR "Could not find mode %x\n", ModeNo); - return 65 * 1000; - } - - RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; - RefreshRateTableIndex += (rateindex - 1); - ClockIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; - if(HwInfo->jChipType < SIS_315H) { - ClockIndex &= 0x3F; - } - Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000; - - return(Clock); } -BOOLEAN -sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex) -{ - USHORT ModeNo = modeno; - USHORT ModeIdIndex = 0, CRT1Index = 0; - USHORT RefreshRateTableIndex = 0; - unsigned char sr_data, cr_data, cr_data2; - - if(HwInfo->jChipType < SIS_315H) { -#ifdef SIS300 - InitTo300Pointer(SiS_Pr, HwInfo); -#else - return FALSE; -#endif - } else { -#ifdef SIS315H - InitTo310Pointer(SiS_Pr, HwInfo); -#else - return FALSE; -#endif - } - - if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE; - - RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; - RefreshRateTableIndex += (rateindex - 1); - CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - - sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; - cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0]; - *htotal = (((cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8)) + 5) * 8; - sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; - cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6]; - cr_data2 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7]; - *vtotal = ((cr_data & 0xFF) | - ((unsigned short)(cr_data2 & 0x01) << 8) | - ((unsigned short)(cr_data2 & 0x20) << 4) | - ((unsigned short)(sr_data & 0x01) << 10)) + 2; - if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & InterlaceMode) - *vtotal *= 2; - - return TRUE; -} - -int -sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - unsigned char modeno, unsigned char rateindex, - struct fb_var_screeninfo *var) -{ - USHORT ModeNo = modeno; - USHORT ModeIdIndex = 0, index = 0; - USHORT RefreshRateTableIndex = 0; - unsigned short VRE, VBE, VRS, VBS, VDE, VT; - unsigned short HRE, HBE, HRS, HBS, HDE, HT; - unsigned char sr_data, cr_data, cr_data2, cr_data3; - int A, B, C, D, E, F, temp, j; - - if(HwInfo->jChipType < SIS_315H) { -#ifdef SIS300 - InitTo300Pointer(SiS_Pr, HwInfo); -#else - return 0; -#endif - } else { -#ifdef SIS315H - InitTo310Pointer(SiS_Pr, HwInfo); -#else - return 0; -#endif - } - - if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0; - - RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; - RefreshRateTableIndex += (rateindex - 1); - index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - - sr_data = SiS_Pr->SiS_CRT1Table[index].CR[14]; - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[0]; - - /* Horizontal total */ - HT = (cr_data & 0xff) | - ((unsigned short) (sr_data & 0x03) << 8); - A = HT + 5; - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[1]; - - /* Horizontal display enable end */ - HDE = (cr_data & 0xff) | - ((unsigned short) (sr_data & 0x0C) << 6); - E = HDE + 1; - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[4]; - - /* Horizontal retrace (=sync) start */ - HRS = (cr_data & 0xff) | - ((unsigned short) (sr_data & 0xC0) << 2); - F = HRS - E - 3; - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[2]; - - /* Horizontal blank start */ - HBS = (cr_data & 0xff) | - ((unsigned short) (sr_data & 0x30) << 4); - - sr_data = SiS_Pr->SiS_CRT1Table[index].CR[15]; - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[3]; - - cr_data2 = SiS_Pr->SiS_CRT1Table[index].CR[5]; - - /* Horizontal blank end */ - HBE = (cr_data & 0x1f) | - ((unsigned short) (cr_data2 & 0x80) >> 2) | - ((unsigned short) (sr_data & 0x03) << 6); - - /* Horizontal retrace (=sync) end */ - HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3); - - temp = HBE - ((E - 1) & 255); - B = (temp > 0) ? temp : (temp + 256); - - temp = HRE - ((E + F + 3) & 63); - C = (temp > 0) ? temp : (temp + 64); - - D = B - F - C; - - if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes == 320) && - ((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes == 200) || - (SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes == 240))) { - - /* Terrible hack, but the correct CRTC data for - * these modes only produces a black screen... - */ - var->left_margin = (400 - 376); - var->right_margin = (328 - 320); - var->hsync_len = (376 - 328); - - } else { - - var->left_margin = D * 8; - var->right_margin = F * 8; - var->hsync_len = C * 8; - - } - - sr_data = SiS_Pr->SiS_CRT1Table[index].CR[13]; - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[6]; - - cr_data2 = SiS_Pr->SiS_CRT1Table[index].CR[7]; - - /* Vertical total */ - VT = (cr_data & 0xFF) | - ((unsigned short) (cr_data2 & 0x01) << 8) | - ((unsigned short)(cr_data2 & 0x20) << 4) | - ((unsigned short) (sr_data & 0x01) << 10); - A = VT + 2; - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[10]; - - /* Vertical display enable end */ - VDE = (cr_data & 0xff) | - ((unsigned short) (cr_data2 & 0x02) << 7) | - ((unsigned short) (cr_data2 & 0x40) << 3) | - ((unsigned short) (sr_data & 0x02) << 9); - E = VDE + 1; - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[8]; - - /* Vertical retrace (=sync) start */ - VRS = (cr_data & 0xff) | - ((unsigned short) (cr_data2 & 0x04) << 6) | - ((unsigned short) (cr_data2 & 0x80) << 2) | - ((unsigned short) (sr_data & 0x08) << 7); - F = VRS + 1 - E; - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[11]; - - cr_data3 = (SiS_Pr->SiS_CRT1Table[index].CR[16] & 0x01) << 5; - - /* Vertical blank start */ - VBS = (cr_data & 0xff) | - ((unsigned short) (cr_data2 & 0x08) << 5) | - ((unsigned short) (cr_data3 & 0x20) << 4) | - ((unsigned short) (sr_data & 0x04) << 8); - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[12]; - - /* Vertical blank end */ - VBE = (cr_data & 0xff) | - ((unsigned short) (sr_data & 0x10) << 4); - temp = VBE - ((E - 1) & 511); - B = (temp > 0) ? temp : (temp + 512); - - cr_data = SiS_Pr->SiS_CRT1Table[index].CR[9]; - - /* Vertical retrace (=sync) end */ - VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); - temp = VRE - ((E + F - 1) & 31); - C = (temp > 0) ? temp : (temp + 32); - - D = B - F - C; - - var->upper_margin = D; - var->lower_margin = F; - var->vsync_len = C; - - if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x8000) - var->sync &= ~FB_SYNC_VERT_HIGH_ACT; - else - var->sync |= FB_SYNC_VERT_HIGH_ACT; - - if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x4000) - var->sync &= ~FB_SYNC_HOR_HIGH_ACT; - else - var->sync |= FB_SYNC_HOR_HIGH_ACT; - - var->vmode = FB_VMODE_NONINTERLACED; - if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x0080) - var->vmode = FB_VMODE_INTERLACED; - else { - j = 0; - while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) { - if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID == - SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].ModeID) { - if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) { - var->vmode = FB_VMODE_DOUBLE; - } - break; - } - j++; - } - } - - if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { -#if 0 /* Do this? */ - var->upper_margin <<= 1; - var->lower_margin <<= 1; - var->vsync_len <<= 1; -#endif - } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { - var->upper_margin >>= 1; - var->lower_margin >>= 1; - var->vsync_len >>= 1; - } - - return 1; -} - -#endif diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h index 7e36b7ac14705..634c0a9d219b1 100644 --- a/drivers/video/sis/init.h +++ b/drivers/video/sis/init.h @@ -3,7 +3,7 @@ /* * Data and prototypes for init.c * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -50,18 +50,24 @@ * */ -#ifndef _INIT_ -#define _INIT_ +#ifndef _INIT_H_ +#define _INIT_H_ #include "osdef.h" #include "initdef.h" -#ifdef LINUX_XF86 +#ifdef SIS_XORG_XF86 #include "sis.h" +#define SIS_NEED_inSISREG +#define SIS_NEED_inSISREGW +#define SIS_NEED_inSISREGL +#define SIS_NEED_outSISREG +#define SIS_NEED_outSISREGW +#define SIS_NEED_outSISREGL #include "sis_regs.h" #endif -#ifdef LINUX_KERNEL +#ifdef SIS_LINUX_KERNEL #include "vgatypes.h" #include "vstruct.h" #ifdef SIS_CP @@ -73,6 +79,10 @@ #include <asm/io.h> #include <linux/fb.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include <video/fbcon.h> +#endif +#include "sis.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #include <linux/sisfb.h> #else #include <video/sisfb.h> @@ -80,44 +90,45 @@ #endif /* Mode numbers */ -static const USHORT ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; -static const USHORT ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53}; -static const USHORT ModeIndex_320x240_FSTN[] = {0x5a, 0x5b, 0x00, 0x00}; /* FSTN */ -static const USHORT ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54}; -static const USHORT ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c}; -static const USHORT ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e}; -static const USHORT ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62}; -static const USHORT ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35}; -static const USHORT ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36}; -static const USHORT ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61}; -static const USHORT ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76}; -static const USHORT ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63}; -static const USHORT ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e}; -static const USHORT ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45}; -static const USHORT ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f}; /* 315 series only */ -static const USHORT ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22}; /* 315 series only */ -static const USHORT ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64}; -static const USHORT ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77}; -static const USHORT ModeIndex_1024x600[] = {0x20, 0x21, 0x00, 0x22}; /* 300 series only */ -static const USHORT ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65}; -static const USHORT ModeIndex_1280x960[] = {0x7c, 0x7d, 0x00, 0x7e}; -static const USHORT ModeIndex_1152x768[] = {0x23, 0x24, 0x00, 0x25}; /* 300 series only */ -static const USHORT ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b}; -static const USHORT ModeIndex_300_1280x768[] = {0x55, 0x5a, 0x00, 0x5b}; -static const USHORT ModeIndex_310_1280x768[] = {0x23, 0x24, 0x00, 0x25}; -static const USHORT ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; -static const USHORT ModeIndex_1280x800[] = {0x14, 0x15, 0x00, 0x16}; -static const USHORT ModeIndex_1360x768[] = {0x48, 0x4b, 0x00, 0x4e}; -static const USHORT ModeIndex_300_1360x1024[]= {0x67, 0x6f, 0x00, 0x72}; /* 300 series, BARCO only */ -static const USHORT ModeIndex_1400x1050[] = {0x26, 0x27, 0x00, 0x28}; /* 315 series only */ -static const USHORT ModeIndex_1680x1050[] = {0x17, 0x18, 0x00, 0x19}; /* 315 series only */ -static const USHORT ModeIndex_1600x1200[] = {0x3c, 0x3d, 0x00, 0x66}; -static const USHORT ModeIndex_1920x1080[] = {0x2c, 0x2d, 0x00, 0x73}; /* 315 series only */ -static const USHORT ModeIndex_1920x1440[] = {0x68, 0x69, 0x00, 0x6b}; -static const USHORT ModeIndex_300_2048x1536[]= {0x6c, 0x6d, 0x00, 0x00}; -static const USHORT ModeIndex_310_2048x1536[]= {0x6c, 0x6d, 0x00, 0x6e}; - -static const USHORT SiS_DRAMType[17][5]={ +static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f}; +static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53}; +static const unsigned short ModeIndex_320x240_FSTN[] = {0x5a, 0x5b, 0x00, 0x00}; /* FSTN */ +static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54}; +static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c}; +static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e}; +static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62}; +static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35}; +static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36}; +static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61}; +static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76}; +static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63}; +static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e}; +static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45}; +static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f}; /* 315 series only */ +static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22}; /* 315 series only */ +static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64}; +static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77}; +static const unsigned short ModeIndex_1024x600[] = {0x20, 0x21, 0x00, 0x22}; /* 300 series only */ +static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65}; +static const unsigned short ModeIndex_1280x960[] = {0x7c, 0x7d, 0x00, 0x7e}; +static const unsigned short ModeIndex_1152x768[] = {0x23, 0x24, 0x00, 0x25}; /* 300 series only */ +static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b}; +static const unsigned short ModeIndex_300_1280x768[] = {0x55, 0x5a, 0x00, 0x5b}; +static const unsigned short ModeIndex_310_1280x768[] = {0x23, 0x24, 0x00, 0x25}; +static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; +static const unsigned short ModeIndex_1280x800[] = {0x14, 0x15, 0x00, 0x16}; +static const unsigned short ModeIndex_1280x854[] = {0x1a, 0x1b, 0x00, 0x1c}; +static const unsigned short ModeIndex_1360x768[] = {0x48, 0x4b, 0x00, 0x4e}; +static const unsigned short ModeIndex_300_1360x1024[]= {0x67, 0x6f, 0x00, 0x72}; /* 300 series, BARCO only */ +static const unsigned short ModeIndex_1400x1050[] = {0x26, 0x27, 0x00, 0x28}; /* 315 series only */ +static const unsigned short ModeIndex_1680x1050[] = {0x17, 0x18, 0x00, 0x19}; /* 315 series only */ +static const unsigned short ModeIndex_1600x1200[] = {0x3c, 0x3d, 0x00, 0x66}; +static const unsigned short ModeIndex_1920x1080[] = {0x2c, 0x2d, 0x00, 0x73}; /* 315 series only */ +static const unsigned short ModeIndex_1920x1440[] = {0x68, 0x69, 0x00, 0x6b}; +static const unsigned short ModeIndex_300_2048x1536[]= {0x6c, 0x6d, 0x00, 0x00}; +static const unsigned short ModeIndex_310_2048x1536[]= {0x6c, 0x6d, 0x00, 0x6e}; + +static const unsigned short SiS_DRAMType[17][5]={ {0x0C,0x0A,0x02,0x40,0x39}, {0x0D,0x0A,0x01,0x40,0x48}, {0x0C,0x09,0x02,0x20,0x35}, @@ -137,7 +148,7 @@ static const USHORT SiS_DRAMType[17][5]={ {0x09,0x08,0x01,0x01,0x00} }; -static const USHORT SiS_SDRDRAM_TYPE[13][5] = +static const unsigned short SiS_SDRDRAM_TYPE[13][5] = { { 2,12, 9,64,0x35}, { 1,13, 9,64,0x44}, @@ -154,7 +165,7 @@ static const USHORT SiS_SDRDRAM_TYPE[13][5] = { 1, 9, 8, 2,0x00} }; -static const USHORT SiS_DDRDRAM_TYPE[4][5] = +static const unsigned short SiS_DDRDRAM_TYPE[4][5] = { { 2,12, 9,64,0x35}, { 2,12, 8,32,0x31}, @@ -162,7 +173,7 @@ static const USHORT SiS_DDRDRAM_TYPE[4][5] = { 2, 9, 8, 4,0x01} }; -static const USHORT SiS_MDA_DAC[] = +static const unsigned char SiS_MDA_DAC[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, @@ -174,7 +185,7 @@ static const USHORT SiS_MDA_DAC[] = 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F }; -static const USHORT SiS_CGA_DAC[] = +static const unsigned char SiS_CGA_DAC[] = { 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, @@ -186,7 +197,7 @@ static const USHORT SiS_CGA_DAC[] = 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F }; -static const USHORT SiS_EGA_DAC[] = +static const unsigned char SiS_EGA_DAC[] = { 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, @@ -198,7 +209,7 @@ static const USHORT SiS_EGA_DAC[] = 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F }; -static const USHORT SiS_VGA_DAC[] = +static const unsigned char SiS_VGA_DAC[] = { 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, @@ -212,7 +223,31 @@ static const USHORT SiS_VGA_DAC[] = 0x0B,0x0C,0x0D,0x0F,0x10 }; -static const SiS_StResInfoStruct SiS_StResInfo[]= +static const struct SiS_St SiS_SModeIDTable[] = +{ + {0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00,0x40}, + {0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00,0x40}, + {0x01,0x1010,0x17,0x02,0x02,0x00,0x01,0x01,0x40}, + {0x03,0x8208,0x03,0x00,0x00,0x00,0x01,0x02,0x40}, + {0x03,0x0210,0x16,0x01,0x01,0x00,0x01,0x02,0x40}, + {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40}, + {0x05,0x9209,0x05,0x00,0x00,0x00,0x00,0x04,0x40}, + {0x06,0x8209,0x06,0x00,0x00,0x00,0x00,0x05,0x40}, + {0x07,0x0000,0x07,0x03,0x03,0x00,0x01,0x03,0x40}, + {0x07,0x0000,0x19,0x02,0x02,0x00,0x01,0x03,0x40}, + {0x0d,0x920a,0x0d,0x00,0x00,0x00,0x00,0x04,0x40}, + {0x0e,0x820a,0x0e,0x00,0x00,0x00,0x00,0x05,0x40}, + {0x0f,0x0202,0x11,0x01,0x01,0x00,0x00,0x05,0x40}, + {0x10,0x0212,0x12,0x01,0x01,0x00,0x00,0x05,0x40}, + {0x11,0x0212,0x1a,0x04,0x04,0x00,0x00,0x05,0x40}, + {0x12,0x0212,0x1b,0x04,0x04,0x00,0x00,0x05,0x40}, + {0x13,0x021b,0x1c,0x00,0x00,0x00,0x00,0x04,0x40}, + {0x12,0x0010,0x18,0x02,0x02,0x00,0x00,0x05,0x40}, + {0x12,0x0210,0x18,0x01,0x01,0x00,0x00,0x05,0x40}, + {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00} +}; + +static const struct SiS_StResInfo_S SiS_StResInfo[]= { { 640,400}, { 640,350}, @@ -221,7 +256,7 @@ static const SiS_StResInfoStruct SiS_StResInfo[]= { 640,480} }; -static const SiS_ModeResInfoStruct SiS_ModeResInfo[] = +static const struct SiS_ModeResInfo_S SiS_ModeResInfo[] = { { 320, 200, 8, 8}, /* 0x00 */ { 320, 240, 8, 8}, /* 0x01 */ @@ -256,11 +291,12 @@ static const SiS_ModeResInfoStruct SiS_ModeResInfo[] = { 1280, 800, 8,16}, /* 0x1e */ { 1920,1080, 8,16}, /* 0x1f */ { 960, 540, 8,16}, /* 0x20 */ - { 960, 600, 8,16} /* 0x21 */ + { 960, 600, 8,16}, /* 0x21 */ + { 1280, 854, 8,16} /* 0x22 */ }; #if defined(SIS300) || defined(SIS315H) -static const SiS_StandTableStruct SiS_StandTable[]= +static const struct SiS_StandTable_S SiS_StandTable[]= { /* 0x00: MD_0_200 */ { @@ -704,11 +740,11 @@ static const SiS_StandTableStruct SiS_StandTable[]= /* SIS VIDEO BRIDGE ----------------------------------------- */ /**************************************************************/ -static const UCHAR SiS_SoftSetting = 0x30; /* RAM setting */ +static const unsigned char SiS_SoftSetting = 0x30; /* RAM setting */ -static const UCHAR SiS_OutputSelect = 0x40; +static const unsigned char SiS_OutputSelect = 0x40; -static const UCHAR SiS_NTSCTiming[] = { +static const unsigned char SiS_NTSCTiming[] = { 0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c, 0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a, 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b, @@ -719,7 +755,7 @@ static const UCHAR SiS_NTSCTiming[] = { 0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00 }; -static const UCHAR SiS_PALTiming[] = { +static const unsigned char SiS_PALTiming[] = { 0x19,0x52,0x35,0x6e,0x04,0x38,0x3d,0x70, 0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d, 0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b, @@ -730,8 +766,8 @@ static const UCHAR SiS_PALTiming[] = { 0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00 }; -static const UCHAR SiS_HiTVExtTiming[] = { - 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64, +static const unsigned char SiS_HiTVExtTiming[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64, 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, 0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13, @@ -741,8 +777,8 @@ static const UCHAR SiS_HiTVExtTiming[] = { 0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00 }; -static const UCHAR SiS_HiTVSt1Timing[] = { - 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65, +static const unsigned char SiS_HiTVSt1Timing[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65, 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, 0x65,0x90,0x7b,0xa8,0x03,0xf0,0x87,0x03, @@ -752,8 +788,8 @@ static const UCHAR SiS_HiTVSt1Timing[] = { 0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00 }; -static const UCHAR SiS_HiTVSt2Timing[] = { - 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64, +static const unsigned char SiS_HiTVSt2Timing[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64, 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, 0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13, @@ -764,8 +800,8 @@ static const UCHAR SiS_HiTVSt2Timing[] = { }; #if 0 -static const UCHAR SiS_HiTVTextTiming[] = { - 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65, +static const unsigned char SiS_HiTVTextTiming[] = { + 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65, 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, 0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f, 0x65,0x90,0xe7,0xbc,0x03,0x0c,0x97,0x03, @@ -776,8 +812,8 @@ static const UCHAR SiS_HiTVTextTiming[] = { }; #endif -static const UCHAR SiS_HiTVGroup3Data[] = { - 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x5f, +static const unsigned char SiS_HiTVGroup3Data[] = { + 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x5f, 0x05,0x21,0xb2,0xb2,0x55,0x77,0x2a,0xa6, 0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20, 0x8c,0x6e,0x60,0x2e,0x58,0x48,0x72,0x44, @@ -787,8 +823,8 @@ static const UCHAR SiS_HiTVGroup3Data[] = { 0x18,0x05,0x18,0x05,0x4c,0xa8,0x01 }; -static const UCHAR SiS_HiTVGroup3Simu[] = { - 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x95, +static const unsigned char SiS_HiTVGroup3Simu[] = { + 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x95, 0xdb,0x20,0xb8,0xb8,0x55,0x47,0x2a,0xa6, 0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20, 0x8c,0x6e,0x60,0x15,0x26,0xd3,0xe4,0x11, @@ -799,8 +835,8 @@ static const UCHAR SiS_HiTVGroup3Simu[] = { }; #if 0 -static const UCHAR SiS_HiTVGroup3Text[] = { - 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0xa7, +static const unsigned char SiS_HiTVGroup3Text[] = { + 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0xa7, 0xf5,0x20,0xce,0xce,0x55,0x47,0x2a,0xa6, 0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20, 0x8c,0x6e,0x60,0x18,0x2c,0x0c,0x20,0x22, @@ -811,136 +847,141 @@ static const UCHAR SiS_HiTVGroup3Text[] = { }; #endif -static const UCHAR SiS_NTSCPhase[] = {0x21,0xed,0xba,0x08}; -static const UCHAR SiS_PALPhase[] = {0x2a,0x05,0xe3,0x00}; -static const UCHAR SiS_PALMPhase[] = {0x21,0xE4,0x2E,0x9B}; -static const UCHAR SiS_PALNPhase[] = {0x21,0xF4,0x3E,0xBA}; -static const UCHAR SiS_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6}; -static const UCHAR SiS_PALPhase2[] = {0x2a,0x09,0x86,0xe9}; -static const UCHAR SiS_PALMPhase2[] = {0x21,0xE6,0xEF,0xA4}; -static const UCHAR SiS_PALNPhase2[] = {0x21,0xF6,0x94,0x46}; -static const UCHAR SiS_SpecialPhase[] = {0x1e,0x8c,0x5c,0x7a}; -static const UCHAR SiS_SpecialPhaseM[]= {0x1e,0x83,0x0a,0xe0}; -static const UCHAR SiS_SpecialPhaseJ[]= {0x25,0xd4,0xfd,0x5e}; - -static const SiS_TVDataStruct SiS_StPALData[] = +static const struct SiS_TVData SiS_StPALData[] = { - { 1, 1, 864, 525,1270, 400, 100, 0, 760,0xf4,0xff,0x1c,0x22}, - { 1, 1, 864, 525,1270, 350, 100, 0, 760,0xf4,0xff,0x1c,0x22}, - { 1, 1, 864, 525,1270, 400, 0, 0, 720,0xf1,0x04,0x1f,0x18}, - { 1, 1, 864, 525,1270, 350, 0, 0, 720,0xf4,0x0b,0x1c,0x0a}, - { 1, 1, 864, 525,1270, 480, 50, 0, 760,0xf4,0xff,0x1c,0x22}, - { 1, 1, 864, 525,1270, 600, 50, 0, 0,0xf4,0xff,0x1c,0x22} + { 1, 1, 864, 525,1270, 400, 100, 0, 760, 0,0xf4,0xff,0x1c,0x22}, + { 1, 1, 864, 525,1270, 350, 100, 0, 760, 0,0xf4,0xff,0x1c,0x22}, + { 1, 1, 864, 525,1270, 400, 0, 0, 720, 0,0xf1,0x04,0x1f,0x18}, + { 1, 1, 864, 525,1270, 350, 0, 0, 720, 0,0xf4,0x0b,0x1c,0x0a}, + { 1, 1, 864, 525,1270, 480, 50, 0, 760, 0,0xf4,0xff,0x1c,0x22}, + { 1, 1, 864, 525,1270, 600, 50, 0, 0,0x300,0xf4,0xff,0x1c,0x22} }; -static const SiS_TVDataStruct SiS_ExtPALData[] = +static const struct SiS_TVData SiS_ExtPALData[] = { - { 27, 10, 848, 448,1270, 530, 50, 0, 50,0xf4,0xff,0x1c,0x22}, /* 640x400, 320x200 */ - { 108, 35, 848, 398,1270, 530, 50, 0, 50,0xf4,0xff,0x1c,0x22}, - { 12, 5, 954, 448,1270, 530, 50, 0, 50,0xf1,0x04,0x1f,0x18}, - { 9, 4, 960, 463,1644, 438, 50, 0, 50,0xf4,0x0b,0x1c,0x0a}, - { 9, 4, 848, 528,1270, 530, 0, 0, 50,0xf5,0xfb,0x1b,0x2a}, /* 640x480, 320x240 */ -/*{ 36, 25,1060, 648,1316, 530, 438, 0, 438,0xeb,0x05,0x25,0x16},*//* 800x600, 400x300 */ - { 36, 25,1060, 648,1270, 530, 438, 0, 438,0xeb,0x05,0x25,0x16}, /* 800x600, 400x300 - better */ - { 3, 2,1080, 619,1270, 540, 438, 0, 438,0xf3,0x00,0x1d,0x20}, /* 720x576 */ - { 1, 1,1170, 821,1270, 520, 686, 0, 686,0xF3,0x00,0x1D,0x20}, /* 1024x768 */ - { 1, 1,1170, 821,1270, 520, 686, 0, 686,0xF3,0x00,0x1D,0x20}, /* 1024x768 (for NTSC equ) */ - { 9, 4, 848, 528,1270, 530, 0, 0, 50,0xf5,0xfb,0x1b,0x2a} /* 720x480 test */ + { 27, 10, 848, 448,1270, 530, 50, 0, 50, 0,0xf4,0xff,0x1c,0x22}, /* 640x400, 320x200 */ + { 108, 35, 848, 398,1270, 530, 50, 0, 50, 0,0xf4,0xff,0x1c,0x22}, + { 12, 5, 954, 448,1270, 530, 50, 0, 50, 0,0xf1,0x04,0x1f,0x18}, + { 9, 4, 960, 463,1644, 438, 50, 0, 50, 0,0xf4,0x0b,0x1c,0x0a}, + { 9, 4, 848, 528,1270, 530, 0, 0, 50, 0,0xf5,0xfb,0x1b,0x2a}, /* 640x480, 320x240 */ + { 36, 25,1060, 648,1270, 530, 438, 0, 438, 0,0xeb,0x05,0x25,0x16}, /* 800x600, 400x300 */ + { 3, 2,1080, 619,1270, 540, 438, 0, 438, 0,0xf3,0x00,0x1d,0x20}, /* 720x576 */ + { 1, 1,1170, 821,1270, 520, 686, 0, 686, 0,0xF3,0x00,0x1D,0x20}, /* 1024x768 */ + { 1, 1,1170, 821,1270, 520, 686, 0, 686, 0,0xF3,0x00,0x1D,0x20}, /* 1024x768 (for NTSC equ) */ + { 9, 4, 848, 528,1270, 530, 0, 0, 50, 0,0xf5,0xfb,0x1b,0x2a} /* 720x480 */ }; -static const SiS_TVDataStruct SiS_StNTSCData[] = +static const struct SiS_TVData SiS_StNTSCData[] = { - { 1, 1, 858, 525,1270, 400, 50, 0, 760,0xf1,0x04,0x1f,0x18}, - { 1, 1, 858, 525,1270, 350, 50, 0, 640,0xf1,0x04,0x1f,0x18}, - { 1, 1, 858, 525,1270, 400, 0, 0, 720,0xf1,0x04,0x1f,0x18}, - { 1, 1, 858, 525,1270, 350, 0, 0, 720,0xf4,0x0b,0x1c,0x0a}, - { 1, 1, 858, 525,1270, 480, 0, 0, 760,0xf1,0x04,0x1f,0x18} + { 1, 1, 858, 525,1270, 400, 50, 0, 760, 0,0xf1,0x04,0x1f,0x18}, + { 1, 1, 858, 525,1270, 350, 50, 0, 640, 0,0xf1,0x04,0x1f,0x18}, + { 1, 1, 858, 525,1270, 400, 0, 0, 720, 0,0xf1,0x04,0x1f,0x18}, + { 1, 1, 858, 525,1270, 350, 0, 0, 720, 0,0xf4,0x0b,0x1c,0x0a}, + { 1, 1, 858, 525,1270, 480, 0, 0, 760, 0,0xf1,0x04,0x1f,0x18} }; -static const SiS_TVDataStruct SiS_ExtNTSCData[] = +static const struct SiS_TVData SiS_ExtNTSCData[] = { - { 143, 65, 858, 443,1270, 440, 171, 0, 171,0xf1,0x04,0x1f,0x18}, /* 640x400, 320x200 */ - { 88, 35, 858, 393,1270, 440, 171, 0, 171,0xf1,0x04,0x1f,0x18}, - { 143, 70, 924, 443,1270, 440, 92, 0, 92,0xf1,0x04,0x1f,0x18}, - { 143, 70, 924, 393,1270, 440, 92, 0, 92,0xf4,0x0b,0x1c,0x0a}, - { 143, 76, 836, 523,1270, 440, 224, 0, 0,0xf1,0x05,0x1f,0x16}, /* 640x480, 320x240 */ - { 143, 120,1056, 643,1270, 440, 0, 128, 0,0xf4,0x10,0x1c,0x00}, /* 800x600, 400x300 */ -/*{ 2, 1, 858, 503,1270, 480, 0, 128, 0,0xee,0x0c,0x22,0x08},*/ /* 720x480 (old, from 650) */ - { 143, 76, 836, 523,1270, 440, 0, 128, 0,0xee,0x0c,0x22,0x08}, /* 720x480 - BETTER (from 300 series) */ -/*{ 65, 64,1056, 791,1270, 480, 638, 0, 0,0xEE,0x0C,0x22,0x08} */ /* 1024x768 (525i) */ - { 1, 1,1100, 811,1412, 440, 0, 128, 0,0xee,0x0c,0x22,0x08}, /* 1024x768 (525i) CORRECTED */ - { 65, 64,1056, 791,1270, 480, 455, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ + { 143, 65, 858, 443,1270, 440, 171, 0, 171, 0,0xf1,0x04,0x1f,0x18}, /* 640x400, 320x200 */ + { 88, 35, 858, 393,1270, 440, 171, 0, 171, 0,0xf1,0x04,0x1f,0x18}, + { 143, 70, 924, 443,1270, 440, 92, 0, 92, 0,0xf1,0x04,0x1f,0x18}, + { 143, 70, 924, 393,1270, 440, 92, 0, 92, 0,0xf4,0x0b,0x1c,0x0a}, + { 143, 76, 836, 523,1270, 440, 224, 0, 0, 0,0xf1,0x05,0x1f,0x16}, /* 640x480, 320x240 */ + { 143, 120,1056, 643,1270, 440, 0, 1, 0, 0,0xf4,0x10,0x1c,0x00}, /* 800x600, 400x300 */ + { 143, 76, 836, 523,1270, 440, 0, 1, 0, 0,0xee,0x0c,0x22,0x08}, /* 720x480 - BETTER (from 300 series) */ + { 1, 1,1100, 811,1412, 440, 0, 1, 0, 0,0xee,0x0c,0x22,0x08}, /* 1024x768 (525i) CORRECTED */ +#if 0 /* flimmert und ist unten abgeschnitten (NTSCHT, NTSC clock) */ + { 65, 64,1056, 791,1270, 480, 455, 0, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 0 + { 1, 1,1100, 811,1412, 440, 0, 1, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 0 + { 1, 1,1120, 821,1516, 420, 0, 1, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 0 + { 1, 1, 938, 821,1516, 420, 0, 1, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 0 /* zoom hin, unten abgeschnitten (NTSC2HT, NTSC1024 clock) */ + { 1, 1,1072, 791,1270, 480, 455, 0, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 1 /* zu weit links (squeezed) (NTSC2HT, NTSC1024 clock) */ + { 1, 1,1100, 846,1270, 440, 455, 0, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif +#if 0 /* zu weit links, rechts abgeschnitten (NTSC2HT, NTSC1024 clock) */ + { 1, 1,1100, 846,1412, 440, 455, 0, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ +#endif }; -static const SiS_TVDataStruct SiS_StHiTVData[] = /* Slave + TVSimu */ +static const struct SiS_TVData SiS_StHiTVData[] = /* Slave + TVSimu */ { - { 1, 1, 0x37c,0x233,0x2b2,0x320, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x37c,0x233,0x2b2,0x320, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x37c,0x233,0x2b2,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 8, 5, 0x41a,0x2ab,0x670,0x3c0,0x150,128, 0, 0x00,0x00,0x00,0x00} + { 1, 1, 0x37c,0x233,0x2b2,0x320, 0, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x320, 0, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x3c0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 8, 5, 0x41a,0x2ab,0x670,0x3c0,0x150, 1, 0, 0, 0, 0, 0, 0} }; -static const SiS_TVDataStruct SiS_St2HiTVData[] = /* Slave */ +static const struct SiS_TVData SiS_St2HiTVData[] = /* Slave */ { - { 3, 1, 0x348,0x1e3,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 3, 1, 0x348,0x1e3,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 5, 2, 0x348,0x233,0x670,0x3c0,0x08d,128, 0, 0x00,0x00,0x00,0x00}, - { 8, 5, 0x41a,0x2ab,0x670,0x3c0,0x17c,128, 0, 0x00,0x00,0x00,0x00} + { 3, 1, 0x348,0x1e3,0x670,0x3c0,0x032, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0, 0, 0, 0, 0}, + { 3, 1, 0x348,0x1e3,0x670,0x3c0,0x032, 0, 0, 0, 0, 0, 0, 0}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0, 0, 0, 0, 0}, + { 5, 2, 0x348,0x233,0x670,0x3c0,0x08d, 1, 0, 0, 0, 0, 0, 0}, + { 8, 5, 0x41a,0x2ab,0x670,0x3c0,0x17c, 1, 0, 0, 0, 0, 0, 0} }; -static const SiS_TVDataStruct SiS_ExtHiTVData[] = -{ - { 6, 1, 0x348,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 3, 1, 0x3c0,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 6, 1, 0x348,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 3, 1, 0x3c0,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 5, 1, 0x348,0x233,0x670,0x3c0,0x166,128, 0, 0x00,0x00,0x00,0x00}, /* 640x480 */ - { 16, 5, 0x41a,0x2ab,0x670,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00}, /* 800x600 */ - { 25, 12, 0x4ec,0x353,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x768 */ - { 5, 4, 0x627,0x464,0x670,0x3c0,0x128, 0, 0, 0x00,0x00,0x00,0x00}, /* 1280x1024 */ - { 4, 1, 0x41a,0x233,0x60c,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00}, /* 800x480 */ - { 5, 2, 0x578,0x293,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x576 */ - { 8, 5, 0x6d6,0x323,0x670,0x3c0,0x128, 0, 0, 0x00,0x00,0x00,0x00}, /* 1280x720 */ - { 137, 32, 0x3d4,0x233,0x663,0x3bf,0x143, 0, 0, 0x00,0x00,0x00,0x00} /* 960x600 */ +static const struct SiS_TVData SiS_ExtHiTVData[] = +{ /* all ok */ + { 6, 1, 0x348,0x233,0x660,0x3c0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 3, 1, 0x3c0,0x233,0x660,0x3c0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 6, 1, 0x348,0x233,0x660,0x3c0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 3, 1, 0x3c0,0x233,0x660,0x3c0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 5, 1, 0x348,0x233,0x670,0x3c0,0x166, 1, 0, 0, 0, 0, 0, 0}, /* 640x480 */ + { 16, 5, 0x41a,0x2ab,0x670,0x3c0,0x143, 1, 0, 0, 0, 0, 0, 0}, /* 800x600 */ + { 25, 12, 0x4ec,0x353,0x670,0x3c0,0x032, 0, 0, 0, 0, 0, 0, 0}, /* 1024x768 */ + { 5, 4, 0x627,0x464,0x670,0x3c0,0x128, 0, 0, 0, 0, 0, 0, 0}, /* 1280x1024 */ + { 4, 1, 0x41a,0x233,0x60c,0x3c0,0x143, 1, 0, 0, 0, 0, 0, 0}, /* 800x480 */ + { 5, 2, 0x578,0x293,0x670,0x3c0,0x032, 0, 0, 0, 0, 0, 0, 0}, /* 1024x576 */ + { 8, 5, 0x6d6,0x323,0x670,0x3c0,0x128, 0, 0, 0, 0, 0, 0, 0}, /* 1280x720 */ + { 8, 3, 0x4ec,0x353,0x670,0x3c0,0x032, 0, 0, 0, 0, 0, 0, 0}, /* 960x600 */ }; -static const SiS_TVDataStruct SiS_St525pData[] = +static const struct SiS_TVData SiS_St525pData[] = { - { 1, 1, 0x6b4,0x20d,0x4f6,0x190, 50, 0, 0x2f8, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x6b4,0x20d,0x4f6,0x15e, 50, 0, 0x280, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x6b4,0x20d,0x4f6,0x190, 50, 0, 0x2f8, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x6b4,0x20d,0x4f6,0x15e, 50, 0, 0x280, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x6b4,0x20d,0x4f6,0x1e0, 0, 0, 0x2f8, 0x00,0x00,0x00,0x00} + { 1, 1, 0x6b4,0x20d,0x4f6,0x190, 50, 0, 0x2f8, 0, 0, 0, 0, 0}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x15e, 50, 0, 0x280, 0, 0, 0, 0, 0}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x190, 50, 0, 0x2f8, 0, 0, 0, 0, 0}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x15e, 50, 0, 0x280, 0, 0, 0, 0, 0}, + { 1, 1, 0x6b4,0x20d,0x4f6,0x1e0, 0, 0, 0x2f8, 0, 0, 0, 0, 0} }; -static const SiS_TVDataStruct SiS_St750pData[] = +static const struct SiS_TVData SiS_St750pData[] = { - { 1, 1, 0x672,0x2ee,0x500,0x190, 50, 0, 0x2f8, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x672,0x2ee,0x500,0x15e, 50, 0, 0x280, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x672,0x2ee,0x500,0x190, 0, 0, 0x2d0, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x672,0x2ee,0x500,0x15e, 0, 0, 0x2d0, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x672,0x2ee,0x500,0x1e0, 0, 0, 0x2f8, 0x00,0x00,0x00,0x00} + { 1, 1, 0x672,0x2ee,0x500,0x190, 50, 0, 0x2f8, 0, 0, 0, 0, 0}, + { 1, 1, 0x672,0x2ee,0x500,0x15e, 50, 0, 0x280, 0, 0, 0, 0, 0}, + { 1, 1, 0x672,0x2ee,0x500,0x190, 0, 0, 0x2d0, 0, 0, 0, 0, 0}, + { 1, 1, 0x672,0x2ee,0x500,0x15e, 0, 0, 0x2d0, 0, 0, 0, 0, 0}, + { 1, 1, 0x672,0x2ee,0x500,0x1e0, 0, 0, 0x2f8, 0, 0, 0, 0, 0} }; -static const SiS_TVDataStruct SiS_Ext750pData[] = -{ - { 143, 65, 0x35a,0x1bb,0x4f6,0x1b8,0x0ab, 0, 0x0ab, 0x00,0x00,0x00,0x00}, - { 88, 35, 0x35a,0x189,0x4f6,0x1b8,0x0ab, 0, 0x0ab, 0x00,0x00,0x00,0x00}, - { 18, 5, 0x339,0x1ae,0x500,0x2d0,0x05c, 0, 0x05c, 0x00,0x00,0x00,0x00}, - { 143, 70, 0x39c,0x189,0x4f6,0x1b8,0x05c, 0, 0x05c, 0x00,0x00,0x00,0x00}, - { 99, 32, 0x320,0x1fe,0x500,0x2d0, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 640x480 */ - { 5, 4, 0x5d8,0x29e,0x500,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 800x600 */ - { 99, 32, 0x320,0x1fe,0x500,0x2d0, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 720x480 test WORKS */ - { 68, 64, 0x55f,0x346,0x500,0x2a8,0x27e, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x768 */ - { 5, 2, 0x3a7,0x226,0x500,0x2a8, 0,128, 0, 0x00,0x00,0x00,0x00}, /* 720x576 */ - { 25, 24, 0x5d8,0x2f3,0x460,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00} /* 1280x720 WORKS */ +static const struct SiS_TVData SiS_Ext750pData[] = +{ /* all ok */ + { 3, 1, 935, 470, 1130, 680, 50, 0, 0, 0, 0, 0, 0, 0}, /* 320x200/640x400 */ + { 24, 7, 935, 420, 1130, 680, 50, 0, 0, 0, 0, 0, 0, 0}, + { 3, 1, 935, 470, 1130, 680, 50, 0, 0, 0, 0, 0, 0, 0}, + { 24, 7, 935, 420, 1130, 680, 50, 0, 0, 0, 0, 0, 0, 0}, + { 2, 1, 1100, 590, 1130, 640, 50, 0, 0, 0, 0, 0, 0, 0}, /* 640x480 */ + { 3, 2, 1210, 690, 1130, 660, 50, 0, 0, 0, 0, 0, 0, 0}, /* 800x600 OK */ + { 2, 1, 1100, 562, 1130, 640, 0, 1, 0, 0, 0, 0, 0, 0}, /* 720x480 OK */ + { 1, 1, 1375, 878, 1130, 640, 638, 0, 0, 0, 0, 0, 0, 0}, /* 1024x768 OK */ + { 5, 3, 1100, 675, 1130, 640, 0, 1, 0, 0, 0, 0, 0, 0}, /* 720/768x576 OK */ + { 25, 24, 1496, 755, 1120, 680, 50, 0, 0, 0, 0, 0, 0, 0} /* 1280x720 OK */ }; -static const SiS_LCDDataStruct SiS_LCD1280x720Data[] = /* 2.03.00 */ +static const struct SiS_LCDData SiS_LCD1280x720Data[] = /* 2.03.00 */ { { 44, 15, 864, 430, 1408, 806 }, /* 640x400 */ { 128, 35, 792, 385, 1408, 806 }, @@ -962,7 +1003,7 @@ static const SiS_LCDDataStruct SiS_LCD1280x720Data[] = /* 2.03.00 */ * (Note: 1280x768_3 is now special for SiS301/NetVista */ -static const SiS_LCDDataStruct SiS_StLCD1280x768_2Data[] = /* 2.03.00 */ +static const struct SiS_LCDData SiS_StLCD1280x768_2Data[] = /* 2.03.00 */ { { 64, 21, 858, 434, 1408, 806 }, /* 640x400 */ { 32, 9, 858, 372, 1408, 806 }, @@ -977,7 +1018,7 @@ static const SiS_LCDDataStruct SiS_StLCD1280x768_2Data[] = /* 2.03.00 */ { 16, 15, 1600, 750, 1600, 806 } /* 1280x720 - from Ext */ }; -static const SiS_LCDDataStruct SiS_ExtLCD1280x768_2Data[] = /* 2.03.00 */ +static const struct SiS_LCDData SiS_ExtLCD1280x768_2Data[] = /* 2.03.00 */ { { 16, 5, 960, 410, 1600, 806 }, /* 640x400 */ { 64, 21, 1152, 364, 1600, 806 }, @@ -993,7 +1034,7 @@ static const SiS_LCDDataStruct SiS_ExtLCD1280x768_2Data[] = /* 2.03.00 */ }; #if 0 /* Not used; _3 now reserved for NetVista (SiS301) */ -static const SiS_LCDDataStruct SiS_LCD1280x768_3Data[] = +static const struct SiS_LCDData SiS_LCD1280x768_3Data[] = { { 64, 25, 1056, 422, 1664, 798 }, /* 640x400 */ { 128, 39, 884, 396, 1408, 806 }, /* ,640 */ @@ -1009,7 +1050,7 @@ static const SiS_LCDDataStruct SiS_LCD1280x768_3Data[] = }; #endif -static const SiS_LCDDataStruct SiS_LCD1280x800Data[] = /* 0.93.12a (TMDS) */ +static const struct SiS_LCDData SiS_LCD1280x800Data[] = /* 0.93.12a (TMDS) */ { { 128, 51, 1122, 412, 1408, 816 }, /* 640x400 */ { 128, 49, 1232, 361, 1408, 816 }, @@ -1024,7 +1065,7 @@ static const SiS_LCDDataStruct SiS_LCD1280x800Data[] = /* 0.93.12a (TMDS) */ { 0, 0, 0, 0, 0, 0 } /* 1280x720 */ }; -static const SiS_LCDDataStruct SiS_LCD1280x800_2Data[] = /* 2.03.00 (LVDS) */ +static const struct SiS_LCDData SiS_LCD1280x800_2Data[] = /* 2.03.00 (LVDS) */ { { 97, 42, 1344, 409, 1552, 812 }, /* 640x400 */ { 97, 35, 1280, 358, 1552, 812 }, @@ -1039,7 +1080,42 @@ static const SiS_LCDDataStruct SiS_LCD1280x800_2Data[] = /* 2.03.00 (LVDS) */ { 97, 90, 1600, 730, 1552, 812 } /* 1280x720 */ }; -static const SiS_LCDDataStruct SiS_LCD1280x960Data[] = +#if 0 +static const struct SiS_LCDData SiS_LCD1280x800_3Data[] = /* 2.02.05a (LVDS); m250 */ +{ + { 128, 51, 1122, 412, 1408, 816 }, /* 640x400 */ + { 128, 49, 1232, 361, 1408, 816 }, + { 128, 51, 1122, 412, 1408, 816 }, + { 128, 49, 1232, 361, 1408, 816 }, + { 8, 3, 880, 491, 1408, 816 }, /* 640x480 */ + { 11, 6, 1024, 612, 1408, 816 }, /* 800x600 */ + { 22, 21, 1400, 784, 1408, 816 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x1024 */ + { 1, 1, 1408, 816, 1408, 816 }, /* 1280x800 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x768 - patch index */ + { 0, 0, 0, 0, 0, 0 } /* 1280x720 */ +}; +#endif + +static const struct SiS_LCDData SiS_LCD1280x854Data[] = /* 2.21.00CS (LVDS) */ +{ + { 56, 15, 936, 410, 1664, 861 }, /* 640x400 */ + { 64, 25, 1586, 355, 1664, 861 }, + { 56, 15, 936, 410, 1664, 861 }, + { 64, 25, 1586, 355, 1664, 861 }, + { 91, 45, 1464, 485, 1664, 861 }, /* 640x480 */ + { 182, 75, 976, 605, 1664, 861 }, /* 800x600 */ + { 91, 66, 1342, 774, 1664, 861 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, /* 1280x1024 */ + { 26, 25, 1708, 807, 1664, 861 }, /* 1280x800 */ + { 13, 12, 1708, 774, 1664, 861 }, /* 1280x768 - patch index */ + { 52, 45, 1708, 725, 1664, 861 }, /* 1280x720 */ + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1664, 861, 1664, 861 } /* 1280x854 */ +}; + +static const struct SiS_LCDData SiS_LCD1280x960Data[] = { { 9, 2, 800, 500, 1800, 1000 }, { 9, 2, 800, 500, 1800, 1000 }, @@ -1049,10 +1125,15 @@ static const SiS_LCDDataStruct SiS_LCD1280x960Data[] = { 30, 11, 1056, 625, 1800, 1000 }, { 5, 3, 1350, 800, 1800, 1000 }, { 1, 1, 1576, 1050, 1576, 1050 }, - { 1, 1, 1800, 1000, 1800, 1000 } + { 1, 1, 1800, 1000, 1800, 1000 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } }; -static const SiS_LCDDataStruct SiS_StLCD1400x1050Data[] = +static const struct SiS_LCDData SiS_StLCD1400x1050Data[] = { { 211, 100, 2100, 408, 1688, 1066 }, { 211, 64, 1536, 358, 1688, 1066 }, @@ -1062,10 +1143,15 @@ static const SiS_LCDDataStruct SiS_StLCD1400x1050Data[] = { 211, 72, 1008, 609, 1688, 1066 }, { 211, 128, 1400, 776, 1688, 1066 }, { 211, 205, 1680, 1041, 1688, 1066 }, - { 1, 1, 1688, 1066, 1688, 1066 } + { 1, 1, 1688, 1066, 1688, 1066 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } }; -static const SiS_LCDDataStruct SiS_ExtLCD1400x1050Data[] = +static const struct SiS_LCDData SiS_ExtLCD1400x1050Data[] = { /* { 211, 60, 1260, 410, 1688, 1066 }, 640x400 (6330) */ { 211, 100, 2100, 408, 1688, 1066 }, /* 640x400 (6325) WORKS */ @@ -1080,10 +1166,13 @@ static const SiS_LCDDataStruct SiS_ExtLCD1400x1050Data[] = { 211, 205, 1680, 1041, 1688, 1066 }, /* 1280x1024 - not used (always unscaled) */ { 1, 1, 1688, 1066, 1688, 1066 }, /* 1400x1050 */ { 0, 0, 0, 0, 0, 0 }, /* kludge */ - { 211, 120, 1400, 730, 1688, 1066 } /* 1280x720 */ + { 211, 120, 1400, 730, 1688, 1066 }, /* 1280x720 */ + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } }; -static const SiS_LCDDataStruct SiS_LCD1680x1050Data[] = +static const struct SiS_LCDData SiS_LCD1680x1050Data[] = { { 95, 24, 1260, 410, 1900, 1066 }, /* 0 640x400 */ { 10, 3, 1710, 362, 1900, 1066 }, @@ -1097,10 +1186,11 @@ static const SiS_LCDDataStruct SiS_LCD1680x1050Data[] = { 95, 69, 1800, 817, 1900, 1066 }, /* 9 1280x800 patch index */ { 13, 9, 1900, 739, 1900, 1066 }, /* 10 1280x720 */ { 95, 94, 1880, 1066, 1900, 1066 }, /* 11 1400x1050 patch index */ - { 1, 1, 1900, 1066, 1900, 1066 } /* 12 1680x1050 */ + { 1, 1, 1900, 1066, 1900, 1066 }, /* 12 1680x1050 */ + { 0, 0, 0, 0, 0, 0 } }; -static const SiS_LCDDataStruct SiS_StLCD1600x1200Data[] = +static const struct SiS_LCDData SiS_StLCD1600x1200Data[] = { {27, 4, 800, 500, 2160, 1250 }, {27, 4, 800, 500, 2160, 1250 }, @@ -1111,10 +1201,14 @@ static const SiS_LCDDataStruct SiS_StLCD1600x1200Data[] = { 5, 2,1350, 800, 2160, 1250 }, {135,88,1600,1100, 2160, 1250 }, {72, 49,1680,1092, 2160, 1250 }, - { 1, 1,2160,1250, 2160, 1250 } + { 1, 1,2160,1250, 2160, 1250 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } }; -static const SiS_LCDDataStruct SiS_ExtLCD1600x1200Data[] = +static const struct SiS_LCDData SiS_ExtLCD1600x1200Data[] = { {72,11, 990, 422, 2160, 1250 }, /* 640x400 (6330) WORKS */ /* {27, 4, 800, 500, 2160, 1250 }, 640x400 (6235) */ @@ -1127,10 +1221,14 @@ static const SiS_LCDDataStruct SiS_ExtLCD1600x1200Data[] = { 5, 2,1350, 800, 2160, 1250 }, {27,16,1500,1064, 2160, 1250 }, /* 1280x1024 */ {72,49,1680,1092, 2160, 1250 }, /* 1400x1050 (6330, was not supported on 6325) */ - { 1, 1,2160,1250, 2160, 1250 } + { 1, 1,2160,1250, 2160, 1250 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } }; -static const SiS_LCDDataStruct SiS_NoScaleData[] = +static const struct SiS_LCDData SiS_NoScaleData[] = { { 1, 1, 800, 449, 800, 449 }, /* 0x00: 320x200, 640x400 */ { 1, 1, 800, 449, 800, 449 }, @@ -1162,14 +1260,18 @@ static const SiS_LCDDataStruct SiS_NoScaleData[] = { 1, 1,1808, 808,1808, 808 }, /* 0x1b: 1360x768 */ { 1, 1,1104, 563,1104, 563 }, /* 0x1c: 960x540 */ { 1, 1,1120, 618,1120, 618 }, /* 0x1d: 960x600 */ - { 1, 1,1408, 816,1408, 816 } /* 0x1f: 1280x800 (TMDS special) */ + { 1, 1,1408, 816,1408, 816 }, /* 0x1f: 1280x800 (TMDS special) */ + { 1, 1,1760,1235,1760,1235 }, /* 0x20: 1600x1200 for LCDA */ + { 1, 1,2048,1320,2048,1320 }, /* 0x21: 1600x1200 for non-SiS LVDS */ + { 1, 1,1664, 861,1664, 861 } /* 0x22: 1280x854 */ }; /**************************************************************/ /* LVDS ----------------------------------------------------- */ /**************************************************************/ -static const SiS_LVDSDataStruct SiS_LVDS320x480Data_1[]= +/* FSTN/DSTN 320x240, 2 variants */ +static const struct SiS_LVDSData SiS_LVDS320x240Data_1[]= { { 848, 433, 400, 525}, { 848, 389, 400, 525}, @@ -1177,157 +1279,40 @@ static const SiS_LVDSDataStruct SiS_LVDS320x480Data_1[]= { 848, 389, 400, 525}, { 848, 518, 400, 525}, {1056, 628, 400, 525}, - { 400, 525, 400, 525}, - { 800, 449,1000, 644}, - { 800, 525,1000, 635} + { 400, 525, 400, 525} /* xSTN */ }; -static const SiS_LVDSDataStruct SiS_LVDS640x480Data_1[]= +static const struct SiS_LVDSData SiS_LVDS320x240Data_2[]= { - { 800, 445, 800, 525}, /* 800, 449, 800, 449 */ + { 800, 445, 800, 525}, { 800, 395, 800, 525}, { 800, 445, 800, 525}, { 800, 395, 800, 525}, { 800, 525, 800, 525}, - { 800, 525, 800, 525}, /* pseudo */ - { 800, 525, 800, 525} /* pseudo */ + {1056, 628,1056, 628}, + { 480, 525, 480, 525} /* xSTN */ }; -/* FSTN 320x240 */ -static const SiS_LVDSDataStruct SiS_LVDS640x480Data_2[]= +static const struct SiS_LVDSData SiS_LVDS640x480Data_1[]= { - { 800, 445, 800, 525}, + { 800, 445, 800, 525}, /* 800, 449, 800, 449 */ { 800, 395, 800, 525}, { 800, 445, 800, 525}, { 800, 395, 800, 525}, - { 800, 525, 800, 525}, - { 800, 525, 800, 525}, /* pseudo */ - { 800, 525, 800, 525} /* pseudo */ + { 800, 525, 800, 525} }; -static const SiS_LVDSDataStruct SiS_LVDS800x600Data_1[]= +static const struct SiS_LVDSData SiS_LVDS800x600Data_1[]= { { 848, 433,1060, 629}, { 848, 389,1060, 629}, { 848, 433,1060, 629}, { 848, 389,1060, 629}, { 848, 518,1060, 629}, - {1056, 628,1056, 628}, {1056, 628,1056, 628} }; -static const SiS_LVDSDataStruct SiS_LVDS800x600Data_2[]= -{ - {1056, 628,1056, 628} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1024x768Data_1[]= -{ - { 840, 438,1344, 806}, - { 840, 409,1344, 806}, - { 840, 438,1344, 806}, - { 840, 409,1344, 806}, - { 840, 518,1344, 806}, /* 640x480 */ - {1050, 638,1344, 806}, /* 800x600 */ - {1344, 806,1344, 806}, /* 1024x768 */ -}; - -static const SiS_LVDSDataStruct SiS_LVDS1024x768Data_2[]= -{ - {1344, 806,1344, 806} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1280x1024Data_1[]= -{ - {1048, 442,1688,1066}, - {1048, 392,1688,1066}, - {1048, 442,1688,1066}, - {1048, 392,1688,1066}, - {1048, 522,1688,1066}, - {1208, 642,1688,1066}, - {1432, 810,1688,1066}, - {1688,1066,1688,1066} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1280x1024Data_2[]= -{ - {1688,1066,1688,1066} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1400x1050Data_1[]= -{ - { 928, 416, 1688,1066}, - { 928, 366, 1688,1066}, - { 928, 416, 1688,1066}, - { 928, 366, 1688,1066}, - { 928, 496, 1688,1066}, - {1088, 616, 1688,1066}, - {1312, 784, 1688,1066}, - {1568,1040, 1688,1066}, - {1688,1066, 1688,1066} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1400x1050Data_2[]= -{ - {1688,1066, 1688,1066} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1600x1200Data_1[]= -{ - {1088, 520, 2048,1320}, - {1088, 470, 2048,1320}, - {1088, 520, 2048,1320}, - {1088, 470, 2048,1320}, - {1088, 600, 2048,1320}, - {1248, 720, 2048,1320}, - {1472, 888, 2048,1320}, - {1728,1144, 2048,1320}, - {1848,1170, 2048,1320}, - {2048,1320, 2048,1320} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1600x1200Data_2[]= -{ - {2048,1320, 2048,1320} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1280x960Data_1[]= -{ - { 840, 438,1344, 806}, - { 840, 409,1344, 806}, - { 840, 438,1344, 806}, - { 840, 409,1344, 806}, - { 840, 518,1344, 806}, - {1050, 638,1344, 806}, - {1344, 806,1344, 806}, - { 800, 449,1280, 801}, - { 800, 525,1280, 813} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1280x960Data_2[]= -{ - {1344, 806,1344, 806} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1280x768Data_1[]= -{ - { 768, 438, 1408, 806}, - { 768, 388, 1408, 806}, - { 768, 438, 1408, 806}, - { 768, 388, 1408, 806}, - { 768, 518, 1408, 806}, - { 928, 638, 1408, 806}, - {1152, 806, 1408, 806}, - {1408, 806, 1408, 806}, - {1408, 806, 1408, 806} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1280x768Data_2[]= -{ - {1408, 806, 1408, 806} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1024x600Data_1[] = +static const struct SiS_LVDSData SiS_LVDS1024x600Data_1[] = { { 840, 604,1344, 800}, { 840, 560,1344, 800}, @@ -1338,124 +1323,18 @@ static const SiS_LVDSDataStruct SiS_LVDS1024x600Data_1[] = {1344, 800,1344, 800} }; -static const SiS_LVDSDataStruct SiS_LVDS1024x600Data_2[] = -{ - {1344, 800,1344, 800} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1152x768Data_1[] = +static const struct SiS_LVDSData SiS_LVDS1024x768Data_1[]= { { 840, 438,1344, 806}, { 840, 409,1344, 806}, { 840, 438,1344, 806}, { 840, 409,1344, 806}, - { 840, 518,1344, 806}, - {1050, 638,1344, 806}, - {1344, 806,1344, 806} -}; - -static const SiS_LVDSDataStruct SiS_LVDS1152x768Data_2[] = -{ - {1344, 806,1344, 806} -}; - -/* Pass 1:1 data */ -static const SiS_LVDSDataStruct SiS_LVDSXXXxXXXData_1[]= -{ - { 800, 449, 800, 449}, - { 800, 449, 800, 449}, - { 900, 449, 900, 449}, - { 900, 449, 900, 449}, - { 800, 525, 800, 525}, /* 640x480 */ - {1056, 628, 1056, 628}, /* 800x600 */ - {1344, 806, 1344, 806}, /* 1024x768 */ - {1688,1066, 1688,1066}, /* 1280x1024 */ /* INSERTED */ - {1688, 806, 1688, 806}, /* 1280x768 */ -}; - -/* Custom data for Barco iQ R series */ -static const SiS_LVDSDataStruct SiS_LVDSBARCO1366Data_1[]= -{ - { 832, 438,1331, 806}, - { 832, 388,1331, 806}, - { 832, 438,1331, 806}, - { 832, 388,1331, 806}, - { 832, 518,1331, 806}, - {1050, 638,1344, 806}, - {1344, 806,1344, 806}, - {1688,1066,1688,1066}, - {1688,1066,1688,1066} /* 1360x1024 */ -}; - -/* Custom data for Barco iQ R series */ -static const SiS_LVDSDataStruct SiS_LVDSBARCO1366Data_2[]= -{ - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1688,1066,1688,1066}, - {1688,1066,1688,1066} /* 1360x1024 */ -}; - -/* Custom data for Barco iQ G series */ -static const SiS_LVDSDataStruct SiS_LVDSBARCO1024Data_1[]= -{ - { 832, 438,1331, 806}, - { 832, 409,1331, 806}, - { 832, 438,1331, 806}, - { 832, 409,1331, 806}, - { 832, 518,1331, 806}, /* 640x480 */ + { 840, 518,1344, 806}, /* 640x480 */ {1050, 638,1344, 806}, /* 800x600 */ {1344, 806,1344, 806}, /* 1024x768 */ }; -/* Custom data for Barco iQ G series */ -static const SiS_LVDSDataStruct SiS_LVDSBARCO1024Data_2[]= -{ - {1344, 806,1344, 806} -}; - -/* Custom data for 848x480 parallel panel */ -static const SiS_LVDSDataStruct SiS_LVDS848x480Data_1[]= -{ - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - {1088, 525,1088, 525}, /* 640x480 TODO */ - {1088, 525,1088, 525}, /* 800x600 TODO */ - {1088, 525,1088, 525}, /* 1024x768 TODO */ - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - {1088, 525,1088, 525}, /* 848x480 */ - {1088, 525,1088, 525} /* 1360x768 TODO */ -}; - -/* Custom data for 848x480 parallel panel */ -static const SiS_LVDSDataStruct SiS_LVDS848x480Data_2[]= -{ - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - {1088, 525,1088, 525}, /* 640x480 */ - {1088, 525,1088, 525}, /* 800x600 */ - {1088, 525,1088, 525}, /* 1024x768 */ - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - { 0, 0, 0, 0}, - {1088, 525,1088, 525}, /* 848x480 */ - {1088, 525,1088, 525} /* 1360x768 TODO */ -}; - -static const SiS_LVDSDataStruct SiS_CHTVUNTSCData[]= +static const struct SiS_LVDSData SiS_CHTVUNTSCData[]= { { 840, 600, 840, 600}, { 840, 600, 840, 600}, @@ -1466,7 +1345,7 @@ static const SiS_LVDSDataStruct SiS_CHTVUNTSCData[]= {1160, 945,1160, 945} }; -static const SiS_LVDSDataStruct SiS_CHTVONTSCData[]= +static const struct SiS_LVDSData SiS_CHTVONTSCData[]= { { 840, 525, 840, 525}, { 840, 525, 840, 525}, @@ -1477,55 +1356,9 @@ static const SiS_LVDSDataStruct SiS_CHTVONTSCData[]= {1160, 840,1160, 840} }; -/* Chrontel TV Skew */ - -static const SiS_LVDSDesStruct SiS_CHTVUNTSCDesData[]= -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS_CHTVONTSCDesData[]= -{ - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS_CHTVUPALDesData[]= -{ - {256, 0}, - {256, 0}, - {256, 0}, - {256, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS_CHTVOPALDesData[]= -{ - {256, 0}, - {256, 0}, - {256, 0}, - {256, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0} -}; - /* CRT1 CRTC data for slave modes */ -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1320x480_1[] = +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1320x240_1[] = { {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f, 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, @@ -1550,48 +1383,7 @@ static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1320x480_1[] = 0x00 }} }; -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_1[] = -{ - {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, - 0x00}}, - {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_1_H[] = -{ - {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x00,0x00,0x00, - 0x00}}, - {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, - 0x83,0x85,0x63,0xba,0x00,0x00,0x00, - 0x00}}, - {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x00,0x00,0x00, - 0x00}}, - {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, - 0x83,0x85,0x63,0xba,0x00,0x00,0x00, - 0x00}}, - {{0x2d,0x28,0x90,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, - 0x00}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_2[] = +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1320x240_2[] = { {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, @@ -1611,12 +1403,17 @@ static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_2[] = {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, 0x01}}, +#if 0 {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e, 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, 0x00}} +#endif + {{0x5f,0x4f,0x83,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xe8,0x0c,0x00,0x00,0x05, + 0x00}}, }; -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_2_H[] = +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1320x240_2_H[] = { {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f, 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, @@ -1641,7 +1438,7 @@ static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_2_H[] = 0x00}} }; -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_3[] = +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1320x240_3[] = { {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, 0xe9,0x8b,0xdf,0x04,0x00,0x00,0x05, @@ -1666,7 +1463,7 @@ static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_3[] = 0x00}} }; -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_3_H[] = +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1320x240_3_H[] = { {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f, 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, @@ -1691,778 +1488,175 @@ static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1640x480_3_H[] = 0x00}} }; -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11024x600_1[] = -{ - {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e, - 0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e, - 0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e, - 0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e, - 0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0xaf,0xba, - 0x3b,0x82,0xdf,0xb0,0x00,0x00,0x01, - 0x00}}, - {{0x7e,0x63,0x82,0x68,0x15,0x1e,0xf1, - 0xae,0x85,0x57,0x1f,0x30,0x00,0x26, - 0x01}}, - {{0xa3,0x7f,0x87,0x86,0x97,0x1e,0xf1, - 0xae,0x85,0x57,0x1f,0x30,0x00,0x02, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11024x600_1_H[] = -{ - {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e, - 0xe2,0x89,0xdf,0x05,0x00,0x00,0x44, - 0x00}}, - {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0, - 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55, - 0x01}}, - {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11024x600_2[] = -{ - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x72,0x88,0xdf,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1, - 0xae,0x84,0x57,0x25,0x30,0x00,0x02, - 0x01}}, - {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x02, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11024x600_2_H[] = -{ - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, - 0x00}}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, - 0x00}}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, - 0x00}}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, - 0x00}}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x72,0x88,0xdf,0x25,0x30,0x00,0x01, - 0x00}}, - {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1, - 0xae,0x84,0x57,0x25,0x30,0x00,0x01, - 0x01}}, - {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11152x768_1[] = -{ - {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x01, - 0x00}}, - {{0x64,0x4f,0x88,0x54,0x9f,0x04,0x3e, - 0xe2,0x89,0xdf,0x05,0x00,0x00,0x01, - 0x00}}, - {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0, - 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26, - 0x01}}, - {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x02, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11152x768_1_H[] = -{ - {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, - 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f, - 0x60,0x87,0x5d,0x83,0x10,0x00,0x44, - 0x00}}, - {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e, - 0xe2,0x89,0xdf,0x05,0x00,0x00,0x44, - 0x00}}, - {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0, - 0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55, - 0x01}}, - {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11152x768_2[] = -{ - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x72,0x88,0xdf,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1, - 0xae,0x84,0x57,0x25,0x30,0x00,0x02, - 0x01}}, - {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x02, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11152x768_2_H[] = -{ - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, - 0x00}}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, - 0x00}}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, - 0x00}}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x31,0x87,0x5d,0x25,0x30,0x00,0x01, - 0x00}}, - {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, - 0x72,0x88,0xdf,0x25,0x30,0x00,0x01, - 0x00}}, - {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1, - 0xae,0x84,0x57,0x25,0x30,0x00,0x01, - 0x01}}, - {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11280x768_1[] = -{ - {{0x5b,0x4f,0x9f,0x55,0x19,0xb4,0x1f, - 0x9c,0x8e,0x8f,0xb5,0x10,0x00,0x01, - 0x00}}, - {{0x5b,0x4f,0x9f,0x55,0x19,0x82,0x1f, - 0x6a,0x8c,0x5d,0x83,0x30,0x00,0x01, - 0x00}}, - {{0x5b,0x4f,0x9f,0x55,0x19,0xb4,0x1f, - 0x9c,0x8e,0x8f,0xb5,0x10,0x00,0x01, - 0x00}}, - {{0x5b,0x4f,0x9f,0x55,0x19,0x82,0x1f, - 0x6a,0x8c,0x5d,0x83,0x30,0x00,0x01, - 0x00}}, - {{0x5b,0x4f,0x9f,0x55,0x19,0x04,0x3e, - 0xec,0x8e,0xdf,0x05,0x20,0x00,0x01, - 0x00}}, - {{0x6f,0x63,0x93,0x69,0x8d,0x7c,0xf0, - 0x64,0x86,0x57,0x7d,0x20,0x00,0x05, - 0x01}}, - {{0x8b,0x7f,0x8f,0x85,0x09,0x24,0xf5, - 0x0c,0x8e,0xff,0x25,0x30,0x00,0x02, - 0x01}}, - {{0xab,0x9f,0x8f,0xa5,0x89,0x24,0xf5, - 0x0c,0x8e,0xff,0x25,0x30,0x00,0x06, - 0x01}}, - {{0xab,0x9f,0x8f,0xa5,0x89,0x24,0xf5, - 0x0c,0x8e,0xff,0x25,0x30,0x00,0x06, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11280x768_1_H[] = +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1640x480_1[] = { - {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f, - 0x93,0x86,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, - 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f, - 0x92,0x86,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, - 0x60,0x84,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f, - 0xe2,0x86,0xdf,0xef,0x10,0x00,0x05, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, 0x00}}, - {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0, - 0x5a,0x8e,0x57,0x67,0x20,0x00,0x01, - 0x01}}, - {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf5, - 0x02,0x86,0xff,0x0f,0x10,0x00,0x01, - 0x01}}, - {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a, - 0x02,0x86,0xff,0x0f,0x09,0x00,0x05, - 0x01}}, - {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a, - 0x02,0x86,0xff,0x0f,0x09,0x00,0x05, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11280x768_2[] = -{ - {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb, - 0x54,0x86,0xdb,0xda,0x00,0x00,0x02, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, 0x00}}, - {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb, - 0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x02, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, 0x00}}, - {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb, - 0x54,0x86,0xdb,0xda,0x00,0x00,0x02, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, 0x00}}, - {{0xab,0x60,0x9f,0x80,0x04,0x24,0xbb, - 0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x02, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xdf,0x04,0x30,0x00,0x05, 0x00}}, - {{0xab,0x60,0x9f,0x80,0x04,0x24,0xb3, - 0x7c,0x8e,0x03,0x02,0x10,0x00,0x02, - 0x01}}, - {{0xab,0x63,0x8f,0x8a,0x8e,0x24,0xf1, - 0xb6,0x88,0x57,0x25,0x10,0x00,0x02, - 0x01}}, - {{0xab,0x7f,0x8f,0x98,0x9c,0x24,0xf5, - 0x0a,0x8c,0xff,0x25,0x30,0x00,0x02, - 0x01}}, - {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5, - 0x0a,0x8c,0xff,0x25,0x30,0x00,0x06, - 0x01}}, - {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5, - 0x0a,0x8c,0xff,0x25,0x30,0x00,0x06, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, 0x01}} }; -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT11280x768_2_H[] = +static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1640x480_1_H[] = { - {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb, - 0x54,0x86,0xdb,0xda,0x00,0x00,0x01, + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x00,0x00,0x00, 0x00}}, - {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb, - 0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x01, + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x83,0x85,0x63,0xba,0x00,0x00,0x00, 0x00}}, - {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb, - 0x54,0x86,0xdb,0xda,0x00,0x00,0x01, + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x00,0x00,0x00, 0x00}}, - {{0x83,0x38,0x97,0x58,0x9c,0x24,0xbb, - 0x3b,0x8d,0xc2,0xc1,0x00,0x00,0x01, + {{0x2d,0x28,0x90,0x2b,0xa0,0xbf,0x1f, + 0x83,0x85,0x63,0xba,0x00,0x00,0x00, 0x00}}, - {{0x83,0x38,0x97,0x58,0x9c,0x24,0xb3, - 0x7c,0x8e,0x03,0x02,0x10,0x00,0x01, - 0x01}}, - {{0x79,0x31,0x9d,0x58,0x9c,0x24,0xf1, - 0xb6,0x88,0x57,0x25,0x10,0x00,0x01, - 0x01}}, - {{0x6b,0x3f,0x8f,0x58,0x9c,0x24,0xf5, - 0x0a,0x8c,0xff,0x25,0x30,0x00,0x01, - 0x01}}, - {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5, - 0x0a,0x8c,0xff,0x25,0x30,0x00,0x06, - 0x01}}, - {{0xab,0x9f,0x8f,0xa8,0x8c,0x24,0xf5, - 0x0a,0x8c,0xff,0x25,0x30,0x00,0x06, - 0x01}} -}; - -/**************************************************************/ -/* COMMON --------------------------------------------------- */ -/**************************************************************/ - -#ifdef LINUX_XF86 - -#define SIS_PL_HSYNCP 0x01 -#define SIS_PL_HSYNCN 0x02 -#define SIS_PL_VSYNCP 0x04 -#define SIS_PL_VSYNCN 0x08 -#define SIS_PL_DVI 0x80 - -typedef struct _SiS_PlasmaModes -{ - const char *name; - ULONG clock; - USHORT HDisplay, HTotal, HFrontPorch, HSyncWidth; - USHORT VDisplay, VTotal, VFrontPorch, VSyncWidth; - UCHAR SyncFlags; -} SiS_PlasmaModes; - -typedef struct _SiS_PlasmaTables -{ - USHORT vendor; - UCHAR productnum; - USHORT product[5]; - const char *DDCnames[5]; - const char *plasmaname; - USHORT maxx,maxy; - USHORT prefx, prefy; - UCHAR modenum; - UCHAR plasmamodes[20]; /* | 0x80 = DVI-capable, | 0x40 = analog */ -} SiS_PlasmaTables; - -static const SiS_PlasmaModes SiS_PlasmaMode[] = { - { "640x400", /* 00: IBM 400@70 */ - 25175, - 640, 800, 17, 64, - 400, 449, 13, 2, - SIS_PL_HSYNCN | SIS_PL_VSYNCN }, - { "640x480", /* 01: VESA 480@72 */ - 31500, - 640, 832, 24, 40, - 480, 520, 9, 3, - SIS_PL_HSYNCN | SIS_PL_VSYNCN }, - { "800x600", /* 02: VESA 600@72 */ - 50000, - 800, 1040, 56, 120, - 600, 666, 37, 6, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "864x480", /* 03: Cereb wide 1 */ - 42526, - 864, 1134, 22, 86, - 480, 500, 1, 3, - SIS_PL_HSYNCP | SIS_PL_VSYNCN }, - { "848x480", /* 04: VESA wide (NEC1) */ - 33750, - 848, 1088, 16, 112, - 480, 517, 6, 8, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1024x576", /* 05: VESA wide (NEC2) */ - 47250, - 1024, 1320, 16, 144, - 576, 596, 2, 4, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1280x720", /* 06: VESA wide (NEC3) */ - 76500, - 1280, 1696, 48, 176, - 720, 750, 4, 8, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1360x765", /* 07: VESA wide (NEC4) */ - 85500, - 1360, 1792, 64, 176, - 765, 795, 4, 8, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1024x600", /* 08: CEREB wide 2 */ - 51200, - 1024, 1352, 51, 164, - 600, 628, 1, 4, - SIS_PL_HSYNCN | SIS_PL_VSYNCP }, - { "1024x768", /* 09: VESA 768@75 */ - 78750, - 1024, 1312, 16, 96, - 768, 800, 1, 3, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1152x864", /* 10: VESA 1152x864@75 */ - 108000, - 1152, 1600, 64, 128, - 864, 900, 1, 3, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1280x1024", /* 11: VESA 1024@60 */ - 108000, - 1280, 1688, 48, 112, - 1024, 1066, 1, 3, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1280x768", /* 12: W_XGA */ - 81000, - 1280, 1688, 48, 112, - 768, 802, 3, 6, - SIS_PL_HSYNCP | SIS_PL_VSYNCN }, - { "1280x768", /* 13: I/O Data W_XGA@56Hz */ - 76064, - 1280, 1688, 48, 112, - 768, 802, 2, 3, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1376x768", /* 14: I/O Wide XGA */ - 87340, - 1376, 1808, 32, 128, - 768, 806, 3, 6, - SIS_PL_HSYNCN | SIS_PL_VSYNCP }, - { "1280x960", /* 15: VESA 960@60 */ - 108000, - 1280, 1800, 96, 112, - 960, 1000, 1, 3, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1400x1050", /* 16: VESA 1050@60Hz */ - 108000, - 1400, 1688, 48, 112, - 1050, 1066, 1, 3, - SIS_PL_HSYNCN | SIS_PL_VSYNCN }, - { "1360x768", /* 17: VESA wide (NEC4/2) */ - 85500, - 1360, 1792, 64, 112, - 765, 795, 3, 6, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "800x600", /* 18: VESA 600@56 */ - 36000, - 800, 1024, 24, 2, - 600, 625, 1, 2, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1072x600", /* 19: Panasonic 1072x600 (sync?) */ - 54100, - 1072, 1424, 48, 176, - 600, 628, 16, 1, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "848x480", /* 20: Panasonic 848x480 (sync?) */ - 33070, /* is 852x480, but we can't use 852 */ - 848, 1068, 20, 40, /* differs from DDC data, better centered */ - 480, 516, 3, 5, /* won't work assumingly, because data is % 8 */ - SIS_PL_HSYNCN | SIS_PL_VSYNCN }, - { "1280x720", /* 21: WIDE720(60) (aka "750p") (Panasonic) */ - 74300, - 1280, 1650,110, 40, - 720, 750, 5, 5, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1280x768", /* 22: 1280x768@56.5 (Panasonic) */ - 76200, /* (According to manual not supported for HDMI; but works) */ - 1280, 1680, 16, 24, - 768, 802, 2, 5, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1280x720@50", /* 23: WIDE720(50) (aka "750p") (Panasonic) */ - 74300, /* Panasonic states 45.0kHz. Not possible. This one works (with some overscan) */ - 1280, 1980,400, 80, - 720, 750, 1, 2, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "720x480", /* 24: 720x480 (aka "525p" and "480p") (Panasonic) */ - 27000, - 720, 856, 40, 32, - 480, 525, 1, 3, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "720x576", /* 25: 720x576 (aka "625p"and "576p") (Panasonic) */ - 27500, - 720, 864, 16, 64, - 576, 625, 5, 6, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, - { "1280x720@50", /* 26: WIDE720(50) (aka "750p") (Generic) */ - 74300, - 1280, 1980,400, 80, - 720, 750, 5, 5, - SIS_PL_HSYNCP | SIS_PL_VSYNCP }, + {{0x2d,0x28,0x90,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}} }; -/* -27.00 720 755 791 858 480 480 484 525 -27.50 720 732 795 864 576 581 587 625 -*/ - -static const SiS_PlasmaTables SiS_PlasmaTable[] = { -#if 0 /* Product IDs missing */ - { 0x38a3, 4, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "NEC PlasmaSync 42VP4/42VP4D/42VP4G/42VP4DG", - 0, 0, - 0, 0, - 11, /* All DVI, except 0, 7, 13 */ - { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0, - 17|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, +BOOLEAN SiSInitPtr(struct SiS_Private *SiS_Pr); +#ifdef SIS_XORG_XF86 +unsigned short SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay, + int Depth, BOOLEAN FSTN, int LCDwith, int LCDheight); #endif -#if 0 /* Product IDs missing */ - { 0x38a3, 3, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "NEC PlasmaSync 42PD1/50PD1/50PD2", - 0, 0, - 0, 0, - 5, /* DVI entirely unknown */ - { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0, 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x38a3, 1, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "NEC PlasmaSync 42PD3", - 0, 0, - 0, 0, - 10, /* DVI entirely unknown */ - { 0|0x40, 1|0xc0, 2|0xc0, 3|0xc0, 4|0xc0, 5|0xc0, 6|0xc0, 7|0x40, 8|0xc0, 9|0xc0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x38a3, 2, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "NEC PlasmaSync 42VM3/61XM1", - 0, 0, - 0, 0, - 11, /* DVI entirely unknown */ - { 0|0x40, 1|0xc0, 2|0xc0, 3|0xc0, 4|0xc0, 5|0xc0, 6|0xc0, 8|0xc0, 9|0xc0,11|0xc0, - 17|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x38a3, 2, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "NEC PlasmaSync 42MP1/42MP2", - 0, 0, - 0, 0, - 6, /* DVI entirely unknown */ - { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0,11|0xc0, 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x38a3, 1, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "NEC PlasmaSync 50MP1", - 0, 0, - 0, 0, - 10, /* DVI entirely unknown */ - { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0, - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, +unsigned short SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, BOOLEAN FSTN, + unsigned short CustomT, int LCDwith, int LCDheight, + unsigned int VBFlags2); +unsigned short SiS_GetModeID_TV(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, unsigned int VBFlags2); +unsigned short SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, unsigned int VBFlags2); + +void SiS_SetReg(SISIOADDRESS port, unsigned short index, unsigned short data); +void SiS_SetRegByte(SISIOADDRESS port, unsigned short data); +void SiS_SetRegShort(SISIOADDRESS port, unsigned short data); +void SiS_SetRegLong(SISIOADDRESS port, unsigned int data); +unsigned char SiS_GetReg(SISIOADDRESS port, unsigned short index); +unsigned char SiS_GetRegByte(SISIOADDRESS port); +unsigned short SiS_GetRegShort(SISIOADDRESS port); +unsigned int SiS_GetRegLong(SISIOADDRESS port); +void SiS_SetRegANDOR(SISIOADDRESS Port, unsigned short Index, unsigned short DataAND, + unsigned short DataOR); +void SiS_SetRegAND(SISIOADDRESS Port,unsigned short Index, unsigned short DataAND); +void SiS_SetRegOR(SISIOADDRESS Port,unsigned short Index, unsigned short DataOR); + +void SiS_DisplayOn(struct SiS_Private *SiS_Pr); +void SiS_DisplayOff(struct SiS_Private *SiS_Pr); +void SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr); +#ifndef SIS_LINUX_KERNEL +void SiSSetLVDSetc(struct SiS_Private *SiS_Pr); #endif - { 0x38a3, 4, - { 0xa482, 0xa483, 0x0000, 0x0000, 0x0000 }, - { "PX-42VM", "", "", "", "" }, - "NEC PlasmaSync 42MP3/42MP4/50MP2/61MP1", - 0, 0, - 0, 0, - 11, /* All DVI except 0, 7, 13, 17 */ - { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,10|0xc0,11|0xc0,13|0x40,14|0xc0, - 17|0x40, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, -#if 0 /* Product IDs missing */ - { 0x38a3, 1, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "NEC PlasmaSync 3300W", - 0, 0, - 0, 0, - 3, - { 0|0x40, 1|0xc0,18|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x38a3, 1, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "NEC PlasmaSync 4200W", - 4, /* DVI entirely unknown */ - { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x38a3, 1, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "NEC PlasmaSync 4210W", - 0, 0, - 0, 0, - 6, /* DVI entirely unknown */ - { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 9|0xc0,11|0xc0, 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x38a3, 1, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "NEC PlasmaSync 5000W", - 0, 0, - 0, 0, - 7, /* DVI entirely unknown */ - { 0|0x40, 1|0xc0, 2|0xc0, 4|0xc0, 7|0x40, 9|0xc0,11|0xc0, 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, -#endif - { 0x412f, 2, - { 0x000c, 0x000b, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "Pioneer 503CMX/PDA-5002", - 0, 0, - 0, 0, - 6, /* DVI unknown */ - { 1|0xc0, 2|0xc0, 9|0xc0,11|0xc0,12|0xc0,15|0xc0, 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x34a9, 1, - { 0xa00e, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "", "", "", "", "" }, - "Panasonic TH-42", - 0, 0, - 0, 0, - 5, /* No DVI output */ - { 1|0x40, 2|0x40, 4|0x40, 9|0x40,15|0x40, 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x34a9, 1, - { 0xa005, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "TH-42PW*4", "", "", "", "" }, - "Panasonic TH-42PW5", - 0, 0, - 0, 0, - 1, /* No special modes otherwise; no DVI. */ - {20|0x40,19|0x40, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x4c2e, 1, - { 0x9b05, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "PLV-Z2", "", "", "", "" }, - "Sanyo PLV-Z2 (non HDCP-mode)", /* HDCP mode would be id 9b06, but not needed */ - 1280, 768, /* as it then advertises correct size */ - 1280, 720, - 1, /* 1280x720, no special modes otherwise */ - {21|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x34a9, 1, - { 0xd034, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "AE500U (DVI-D)", "", "", "", "" }, - "Panasonic AE500U", - 1280, 768, - 1280, 720, - 1, /* 1280x720, no special modes otherwise */ - {21|0xc0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x34a9, 1, - { 0xd043, 0x0000, 0x0000, 0x0000, 0x0000 }, - { "AE700U (HDMI)", "", "", "", "" }, - "Panasonic AE700U", - 1360, 768, - 1280, 720, - 6, /* 1280x720/60, 1280x720/50, 1280x768@56(digital/analog), 720x480, 720x576 */ - {21|0xc0,23|0xc0,22|0x80,13|0x40,24|0x80,25|0x80, 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } - }, - { 0x0000 } -}; +void SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable); +void SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable); +unsigned short SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +BOOLEAN SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr); +#ifndef SIS_LINUX_KERNEL +void SiS_GetVBType(struct SiS_Private *SiS_Pr); #endif -#ifdef LINUX_XF86 -USHORT SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, - int Depth, BOOLEAN FSTN, int LCDwith, int LCDheight); +BOOLEAN SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, + unsigned short *ModeIdIndex); +unsigned short SiS_GetModePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +unsigned short SiS_GetRefCRTVCLK(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide); +unsigned short SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide); +unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr,unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI); +#ifdef SIS300 +void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *idx1, + unsigned short *idx2); +unsigned short SiS_GetFIFOThresholdB300(unsigned short idx1, unsigned short idx2); +unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index); #endif -USHORT SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN, - USHORT CustomT, int LCDwith, int LCDheight); -USHORT SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth); -USHORT SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth); - -void SiS_SetReg(SISIOADDRESS port, USHORT index, USHORT data); -void SiS_SetRegByte(SISIOADDRESS port, USHORT data); -void SiS_SetRegShort(SISIOADDRESS port, USHORT data); -void SiS_SetRegLong(SISIOADDRESS port, ULONG data); -UCHAR SiS_GetReg(SISIOADDRESS port, USHORT index); -UCHAR SiS_GetRegByte(SISIOADDRESS port); -USHORT SiS_GetRegShort(SISIOADDRESS port); -ULONG SiS_GetRegLong(SISIOADDRESS port); -void SiS_SetRegANDOR(SISIOADDRESS Port, USHORT Index, USHORT DataAND, USHORT DataOR); -void SiS_SetRegAND(SISIOADDRESS Port,USHORT Index, USHORT DataAND); -void SiS_SetRegOR(SISIOADDRESS Port,USHORT Index, USHORT DataOR); -void SiS_DisplayOn(SiS_Private *SiS_Pr); -void SiS_DisplayOff(SiS_Private *SiS_Pr); -void SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr); -BOOLEAN SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -void SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable); -void SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable); -BOOLEAN SiS_SearchModeID(SiS_Private *SiS_Pr, USHORT *ModeNo, USHORT *ModeIdIndex); -UCHAR SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); -USHORT SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); -USHORT SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo); -void SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT ModeIdIndex); -void SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); - -#ifdef LINUX_XF86 -BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch); -BOOLEAN SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, - DisplayModePtr mode, BOOLEAN IsCustom); -BOOLEAN SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, - DisplayModePtr mode, BOOLEAN IsCustom); -BOOLEAN SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, - DisplayModePtr mode, BOOLEAN IsCustom); -int SiSTranslateToVESA(ScrnInfoPtr pScrn, int modenumber); -int SiSTranslateToOldMode(int modenumber); -BOOLEAN SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_INFO); -USHORT SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags); -DisplayModePtr SiSBuildBuiltInModeList(ScrnInfoPtr pScrn, BOOLEAN includelcdmodes, BOOLEAN isfordvi); -int SiS_FindPanelFromDB(SISPtr pSiS, USHORT panelvendor, USHORT panelproduct, int *maxx, int *maxy, int *prefx, int *prefy); -void SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, UCHAR *p2b, UCHAR *p2c); -#else -BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo); +void SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); +#ifdef SIS_XORG_XF86 +BOOLEAN SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo, + BOOLEAN dosetpitch); +BOOLEAN SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, + DisplayModePtr mode, BOOLEAN IsCustom); +BOOLEAN SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, + DisplayModePtr mode, BOOLEAN IsCustom); +BOOLEAN SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, + DisplayModePtr mode, BOOLEAN IsCustom); +#endif +#ifdef SIS_LINUX_KERNEL +BOOLEAN SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +#endif +void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth); +void SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +#ifdef SIS_XORG_XF86 +void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres, + int yres, DisplayModePtr current); +#endif +#ifdef SIS_LINUX_KERNEL +void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres, + int yres, struct fb_var_screeninfo *var, BOOLEAN writeres); #endif -#ifdef LINUX_KERNEL -int sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - UCHAR modeno, UCHAR rateindex); -int sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - UCHAR modeno, UCHAR rateindex, - struct fb_var_screeninfo *var); -BOOLEAN sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - UCHAR modeno, int *htotal, int *vtotal, UCHAR rateindex); +/* From init301.c: */ +extern void SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, int chkcrt2mode); +extern void SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern void SiS_SetYPbPr(struct SiS_Private *SiS_Pr); +extern void SiS_SetTVMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern void SiS_UnLockCRT2(struct SiS_Private *SiS_Pr); +extern void SiS_DisableBridge(struct SiS_Private *); +extern BOOLEAN SiS_SetCRT2Group(struct SiS_Private *, unsigned short); +extern unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern void SiS_WaitRetrace1(struct SiS_Private *SiS_Pr); +extern unsigned short SiS_GetResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short tempax); +extern unsigned short SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI); +extern BOOLEAN SiS_IsVAMode(struct SiS_Private *); +extern BOOLEAN SiS_IsDualEdge(struct SiS_Private *); + +#ifdef SIS_XORG_XF86 +/* From other modules: */ +extern unsigned short SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, + unsigned int VBFlags); +extern unsigned char SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, unsigned short offset, + unsigned char value); +extern unsigned char SiS_GetSetModeID(ScrnInfoPtr pScrn, unsigned char id); +extern unsigned short SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, + unsigned int VBFlags); #endif -/* init301.c: */ -extern void SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo, int chkcrt2mode); -extern void SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo); -extern void SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -extern void SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo); -extern void SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -extern void SiS_DisableBridge(SiS_Private *, PSIS_HW_INFO); -extern BOOLEAN SiS_SetCRT2Group(SiS_Private *, PSIS_HW_INFO, USHORT); -extern USHORT SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo); -extern void SiS_WaitRetrace1(SiS_Private *SiS_Pr); -extern USHORT SiS_GetResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); -extern USHORT SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempax); -extern USHORT SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo); -extern BOOLEAN SiS_IsVAMode(SiS_Private *, PSIS_HW_INFO); -extern BOOLEAN SiS_IsDualEdge(SiS_Private *, PSIS_HW_INFO); - -#ifdef LINUX_XF86 -/* From other sis driver modules: */ -extern int SiS_compute_vclk(int Clock, int *out_n, int *out_dn, int *out_div, - int *out_sbit, int *out_scale); -extern void SiSCalcClock(ScrnInfoPtr pScrn, int clock, int max_VLD, unsigned int *vclk); - -extern UCHAR SiS_GetSetBIOSScratch(ScrnInfoPtr pScrn, USHORT offset, UCHAR value); -extern UCHAR SiS_GetSetModeID(ScrnInfoPtr pScrn, UCHAR id); -extern USHORT SiS_GetModeNumber(ScrnInfoPtr pScrn, DisplayModePtr mode, ULONG VBFlags); +#ifdef SIS_LINUX_KERNEL +#ifdef SIS300 +extern unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg); +extern void sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, + unsigned int val); +#endif +#ifdef SIS315H +extern void sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, + unsigned char val); +extern unsigned int sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg); +#endif #endif #endif diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c index 274dacd54bb82..2d88f908170aa 100644 --- a/drivers/video/sis/init301.c +++ b/drivers/video/sis/init301.c @@ -2,11 +2,12 @@ /* $XdotOrg$ */ /* * Mode initializing code (CRT2 section) - * for SiS 300/305/540/630/730 and - * SiS 315/550/650/M650/651/661FX/M661xX/740/741(GX)/M741/330/660/M660/760/M760 - * (Universal module for Linux kernel framebuffer and XFree86/X.org 4.x) + * for SiS 300/305/540/630/730, + * SiS 315/550/[M]650/651/[M]661[FGM]X/[M]74x[GX]/330/[M]76x[GX], + * XGI V3XT/V5/V8, Z7 + * (Universal module for Linux kernel framebuffer and X.org/XFree86 4.x) * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -38,7 +39,7 @@ * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -54,20 +55,20 @@ * Formerly based on non-functional code-fragements for 300 series by SiS, Inc. * Used by permission. * - * TW says: This code looks awful, I know. But please don't do anything about - * this otherwise debugging will be hell. - * The code is extremely fragile as regards the different chipsets, different - * video bridges and combinations thereof. If anything is changed, extreme - * care has to be taken that that change doesn't break it for other chipsets, - * bridges or combinations thereof. - * All comments in this file are by me, regardless if marked TW or not. - * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #if 1 #define SET_EMI /* 302LV/ELV: Set EMI values */ #endif +#if 1 +#define SET_PWD /* 301/302LV: Set PWD */ +#endif + #define COMPAL_HACK /* Needed for Compal 1400x1050 (EMI) */ #define COMPAQ_HACK /* Needed for Inventec/Compaq 1280x1024 (EMI) */ #define ASUS_HACK /* Needed for Asus A2H 1024x768 (EMI) */ @@ -85,26 +86,35 @@ #define SiS_I2CDELAY 1000 #define SiS_I2CDELAYSHORT 150 -static USHORT SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr); -static void SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx); +static unsigned short SiS_GetBIOSLCDResInfo(struct SiS_Private *SiS_Pr); +#ifdef SIS_LINUX_KERNEL +static void SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); +#endif /*********************************************/ /* HELPER: Lock/Unlock CRT2 */ /*********************************************/ void -SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_UnLockCRT2(struct SiS_Private *SiS_Pr) { - if(HwInfo->jChipType >= SIS_315H) + if(SiS_Pr->ChipType == XGI_20) + return; + else if(SiS_Pr->ChipType >= SIS_315H) SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01); else SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01); } -static void -SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +#ifdef SIS_LINUX_KERNEL +static +#endif +void +SiS_LockCRT2(struct SiS_Private *SiS_Pr) { - if(HwInfo->jChipType >= SIS_315H) + if(SiS_Pr->ChipType == XGI_20) + return; + else if(SiS_Pr->ChipType >= SIS_315H) SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE); else SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE); @@ -115,9 +125,9 @@ SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /*********************************************/ static void -SiS_SetRegSR11ANDOR(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DataAND, USHORT DataOR) +SiS_SetRegSR11ANDOR(struct SiS_Private *SiS_Pr, unsigned short DataAND, unsigned short DataOR) { - if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->ChipType >= SIS_661) { DataAND &= 0x0f; DataOR &= 0x0f; } @@ -129,12 +139,12 @@ SiS_SetRegSR11ANDOR(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DataAND, US /*********************************************/ #ifdef SIS315H -static UCHAR * -GetLCDStructPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +static unsigned char * +GetLCDStructPtr661(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - UCHAR *myptr = NULL; - USHORT romindex = 0, reg = 0, idx = 0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned char *myptr = NULL; + unsigned short romindex = 0, reg = 0, idx = 0; /* Use the BIOS tables only for LVDS panels; TMDS is unreliable * due to the variaty of panels the BIOS doesn't know about. @@ -144,15 +154,15 @@ GetLCDStructPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) */ if((SiS_Pr->SiS_ROMNew) && - ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) || (!SiS_Pr->PanelSelfDetected))) { + ((SiS_Pr->SiS_VBType & VB_SISLVDS) || (!SiS_Pr->PanelSelfDetected))) { - if(HwInfo->jChipType < SIS_661) reg = 0x3c; - else reg = 0x7d; + if(SiS_Pr->ChipType < SIS_661) reg = 0x3c; + else reg = 0x7d; idx = (SiS_GetReg(SiS_Pr->SiS_P3d4,reg) & 0x1f) * 26; if(idx < (8*26)) { - myptr = (UCHAR *)&SiS_LCDStruct661[idx]; + myptr = (unsigned char *)&SiS_LCDStruct661[idx]; } romindex = SISGETROMW(0x100); if(romindex) { @@ -163,11 +173,11 @@ GetLCDStructPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) return myptr; } -static USHORT -GetLCDStructPtr661_2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +static unsigned short +GetLCDStructPtr661_2(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT romptr = 0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr = 0; /* Use the BIOS tables only for LVDS panels; TMDS is unreliable * due to the variaty of panels the BIOS doesn't know about. @@ -177,12 +187,12 @@ GetLCDStructPtr661_2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) */ if((SiS_Pr->SiS_ROMNew) && - ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) || (!SiS_Pr->PanelSelfDetected))) { + ((SiS_Pr->SiS_VBType & VB_SISLVDS) || (!SiS_Pr->PanelSelfDetected))) { romptr = SISGETROMW(0x102); romptr += ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) * SiS_Pr->SiS661LCD2TableSize); } - return(romptr); + return romptr; } #endif @@ -191,186 +201,187 @@ GetLCDStructPtr661_2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /*********************************************/ static BOOLEAN -SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RRTI, USHORT *i, PSIS_HW_INFO HwInfo) +SiS_AdjustCRT2Rate(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RRTI, unsigned short *i) { - USHORT checkmask=0,modeid,infoflag; + unsigned short checkmask=0, modeid, infoflag; - modeid = SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID; + modeid = SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID; - if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { - checkmask |= SupportRAMDAC2; - if(HwInfo->jChipType >= SIS_315H) { - checkmask |= SupportRAMDAC2_135; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - checkmask |= SupportRAMDAC2_162; - if(SiS_Pr->SiS_VBType & VB_SIS301C) { - checkmask |= SupportRAMDAC2_202; - } - } - } + checkmask |= SupportRAMDAC2; + if(SiS_Pr->ChipType >= SIS_315H) { + checkmask |= SupportRAMDAC2_135; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + checkmask |= SupportRAMDAC2_162; + if(SiS_Pr->SiS_VBType & VB_SISRAMDAC202) { + checkmask |= SupportRAMDAC2_202; + } + } + } - } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - checkmask |= SupportLCD; - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_VBType & VB_SISVB) { - if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { - if(modeid == 0x2e) checkmask |= Support64048060Hz; - } - } - } + checkmask |= SupportLCD; + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(modeid == 0x2e) checkmask |= Support64048060Hz; + } + } + } - } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - checkmask |= SupportHiVision; + checkmask |= SupportHiVision; - } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750|SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) { + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750|SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) { - checkmask |= SupportTV; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - checkmask |= SupportTV1024; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { - checkmask |= SupportYPbPr750p; - } - } - } + checkmask |= SupportTV; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + checkmask |= SupportTV1024; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + checkmask |= SupportYPbPr750p; + } + } + } - } + } - } else { /* LVDS */ + } else { /* LVDS */ - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - checkmask |= SupportCHTV; - } - } + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + checkmask |= SupportCHTV; + } + } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - checkmask |= SupportLCD; - } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + checkmask |= SupportLCD; + } - } + } - /* Look backwards in table for matching CRT2 mode */ - for(; SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID == modeid; (*i)--) { - infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag; - if(infoflag & checkmask) return TRUE; - if((*i) == 0) break; - } + /* Look backwards in table for matching CRT2 mode */ + for(; SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID == modeid; (*i)--) { + infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag; + if(infoflag & checkmask) return TRUE; + if((*i) == 0) break; + } - /* Look through the whole mode-section of the table from the beginning - * for a matching CRT2 mode if no mode was found yet. - */ - for((*i) = 0; ; (*i)++) { - if(SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID != modeid) break; - infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag; - if(infoflag & checkmask) return TRUE; - } - return FALSE; + /* Look through the whole mode-section of the table from the beginning + * for a matching CRT2 mode if no mode was found yet. + */ + for((*i) = 0; ; (*i)++) { + if(SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID != modeid) break; + infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag; + if(infoflag & checkmask) return TRUE; + } + return FALSE; } /*********************************************/ /* Get rate index */ /*********************************************/ -USHORT -SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo) -{ - SHORT LCDRefreshIndex[] = { 0x00, 0x00, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x00 }; - USHORT RRTI,i,backup_i; - USHORT modeflag,index,temp,backupindex; +unsigned short +SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) +{ + unsigned short RRTI,i,backup_i; + unsigned short modeflag,index,temp,backupindex; + static const unsigned short LCDRefreshIndex[] = { + 0x00, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00 + }; - /* Do NOT check for UseCustomMode here, will skrew up FIFO */ - if(ModeNo == 0xfe) return 0; + /* Do NOT check for UseCustomMode here, will skrew up FIFO */ + if(ModeNo == 0xfe) return 0; - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - if(modeflag & HalfDCLK) return 0; - } - } + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(modeflag & HalfDCLK) return 0; + } + } - if(ModeNo < 0x14) return 0xFFFF; + if(ModeNo < 0x14) return 0xFFFF; - index = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x33) >> SiS_Pr->SiS_SelectCRT2Rate) & 0x0F; - backupindex = index; + index = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x33) >> SiS_Pr->SiS_SelectCRT2Rate) & 0x0F; + backupindex = index; - if(index > 0) index--; + if(index > 0) index--; - if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { - if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_VBType & VB_NoLCD) index = 0; - else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index = backupindex = 0; - } - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - if(!(SiS_Pr->SiS_VBType & VB_NoLCD)) { - temp = LCDRefreshIndex[SiS_GetBIOSLCDResInfo(SiS_Pr)]; - if(index > temp) index = temp; - } - } - } else { - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) index = 0; - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) index = 0; - } - } - } + if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_VBType & VB_NoLCD) index = 0; + else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index = backupindex = 0; + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_VBType & VB_NoLCD)) { + temp = LCDRefreshIndex[SiS_GetBIOSLCDResInfo(SiS_Pr)]; + if(index > temp) index = temp; + } + } + } else { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) index = 0; + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) index = 0; + } + } + } - RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; - ModeNo = SiS_Pr->SiS_RefIndex[RRTI].ModeID; + RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + ModeNo = SiS_Pr->SiS_RefIndex[RRTI].ModeID; - if(HwInfo->jChipType >= SIS_315H) { - if(!(SiS_Pr->SiS_VBInfo & DriverMode)) { - if( (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x105) || - (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x107) ) { - if(backupindex <= 1) RRTI++; - } - } - } + if(SiS_Pr->ChipType >= SIS_315H) { + if(!(SiS_Pr->SiS_VBInfo & DriverMode)) { + if( (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x105) || + (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x107) ) { + if(backupindex <= 1) RRTI++; + } + } + } - i = 0; - do { - if(SiS_Pr->SiS_RefIndex[RRTI + i].ModeID != ModeNo) break; - temp = SiS_Pr->SiS_RefIndex[RRTI + i].Ext_InfoFlag; - temp &= ModeTypeMask; - if(temp < SiS_Pr->SiS_ModeType) break; - i++; - index--; - } while(index != 0xFFFF); - - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - temp = SiS_Pr->SiS_RefIndex[RRTI + i - 1].Ext_InfoFlag; - if(temp & InterlaceMode) i++; - } - } + i = 0; + do { + if(SiS_Pr->SiS_RefIndex[RRTI + i].ModeID != ModeNo) break; + temp = SiS_Pr->SiS_RefIndex[RRTI + i].Ext_InfoFlag; + temp &= ModeTypeMask; + if(temp < SiS_Pr->SiS_ModeType) break; + i++; + index--; + } while(index != 0xFFFF); + + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + temp = SiS_Pr->SiS_RefIndex[RRTI + i - 1].Ext_InfoFlag; + if(temp & InterlaceMode) i++; + } + } - i--; + i--; - if((SiS_Pr->SiS_SetFlag & ProgrammingCRT2) && (!(SiS_Pr->SiS_VBInfo & DisableCRT2Display))) { - backup_i = i; - if(!(SiS_AdjustCRT2Rate(SiS_Pr, ModeNo, ModeIdIndex, RRTI, &i, HwInfo))) { - i = backup_i; - } - } + if((SiS_Pr->SiS_SetFlag & ProgrammingCRT2) && (!(SiS_Pr->SiS_VBInfo & DisableCRT2Display))) { + backup_i = i; + if(!(SiS_AdjustCRT2Rate(SiS_Pr, ModeNo, ModeIdIndex, RRTI, &i))) { + i = backup_i; + } + } - return(RRTI + i); + return (RRTI + i); } /*********************************************/ @@ -378,15 +389,15 @@ SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ static void -SiS_SaveCRT2Info(SiS_Private *SiS_Pr, USHORT ModeNo) +SiS_SaveCRT2Info(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { - USHORT temp1,temp2; + unsigned short temp1, temp2; - /* Store CRT1 ModeNo in CR34 */ - SiS_SetReg(SiS_Pr->SiS_P3d4,0x34,ModeNo); - temp1 = (SiS_Pr->SiS_VBInfo & SetInSlaveMode) >> 8; - temp2 = ~(SetInSlaveMode >> 8); - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x31,temp2,temp1); + /* Store CRT1 ModeNo in CR34 */ + SiS_SetReg(SiS_Pr->SiS_P3d4,0x34,ModeNo); + temp1 = (SiS_Pr->SiS_VBInfo & SetInSlaveMode) >> 8; + temp2 = ~(SetInSlaveMode >> 8); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x31,temp2,temp1); } /*********************************************/ @@ -395,35 +406,35 @@ SiS_SaveCRT2Info(SiS_Private *SiS_Pr, USHORT ModeNo) #ifdef SIS300 static BOOLEAN -SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_CR36BIOSWord23b(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT temp,temp1; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short temp,temp1; - if(SiS_Pr->SiS_UseROM) { - if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { - temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f); - temp1 = SISGETROMW(0x23b); - if(temp1 & temp) return TRUE; - } - } - return FALSE; + if(SiS_Pr->SiS_UseROM) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f); + temp1 = SISGETROMW(0x23b); + if(temp1 & temp) return TRUE; + } + } + return FALSE; } static BOOLEAN -SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_CR36BIOSWord23d(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT temp,temp1; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short temp,temp1; - if(SiS_Pr->SiS_UseROM) { - if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { - temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f); - temp1 = SISGETROMW(0x23d); - if(temp1 & temp) return TRUE; - } - } - return FALSE; + if(SiS_Pr->SiS_UseROM) { + if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { + temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f); + temp1 = SISGETROMW(0x23d); + if(temp1 & temp) return TRUE; + } + } + return FALSE; } #endif @@ -432,85 +443,76 @@ SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /*********************************************/ void -SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime) +SiS_DDC2Delay(struct SiS_Private *SiS_Pr, unsigned int delaytime) { - USHORT i, j; + unsigned int i, j; - for(i=0; i<delaytime; i++) { - j += SiS_GetReg(SiS_Pr->SiS_P3c4,0x05); - } + for(i = 0; i < delaytime; i++) { + j += SiS_GetReg(SiS_Pr->SiS_P3c4,0x05); + } } #if defined(SIS300) || defined(SIS315H) static void -SiS_GenericDelay(SiS_Private *SiS_Pr, USHORT delay) +SiS_GenericDelay(struct SiS_Private *SiS_Pr, unsigned short delay) { - USHORT temp,flag; - - flag = SiS_GetRegByte(0x61) & 0x10; - - while(delay) { - temp = SiS_GetRegByte(0x61) & 0x10; - if(temp == flag) continue; - flag = temp; - delay--; - } + SiS_DDC2Delay(SiS_Pr, delay * 36); } #endif #ifdef SIS315H static void -SiS_LongDelay(SiS_Private *SiS_Pr, USHORT delay) +SiS_LongDelay(struct SiS_Private *SiS_Pr, unsigned short delay) { - while(delay--) { - SiS_GenericDelay(SiS_Pr,0x19df); - } + while(delay--) { + SiS_GenericDelay(SiS_Pr, 6623); + } } #endif #if defined(SIS300) || defined(SIS315H) static void -SiS_ShortDelay(SiS_Private *SiS_Pr, USHORT delay) +SiS_ShortDelay(struct SiS_Private *SiS_Pr, unsigned short delay) { - while(delay--) { - SiS_GenericDelay(SiS_Pr,0x42); - } + while(delay--) { + SiS_GenericDelay(SiS_Pr, 66); + } } #endif static void -SiS_PanelDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DelayTime) +SiS_PanelDelay(struct SiS_Private *SiS_Pr, unsigned short DelayTime) { #if defined(SIS300) || defined(SIS315H) - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT PanelID, DelayIndex, Delay=0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short PanelID, DelayIndex, Delay=0; #endif - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBType & VB_SIS301) PanelID &= 0xf7; - if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x18) & 0x10)) PanelID = 0x12; + if(SiS_Pr->SiS_VBType & VB_SIS301) PanelID &= 0xf7; + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x18) & 0x10)) PanelID = 0x12; } DelayIndex = PanelID >> 4; if((DelayTime >= 2) && ((PanelID & 0x0f) == 1)) { - Delay = 3; + Delay = 3; } else { - if(DelayTime >= 2) DelayTime -= 2; - if(!(DelayTime & 0x01)) { - Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0]; - } else { - Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; - } + if(DelayTime >= 2) DelayTime -= 2; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; + } if(SiS_Pr->SiS_UseROM) { - if(ROMAddr[0x220] & 0x40) { - if(!(DelayTime & 0x01)) Delay = (USHORT)ROMAddr[0x225]; - else Delay = (USHORT)ROMAddr[0x226]; - } - } + if(ROMAddr[0x220] & 0x40) { + if(!(DelayTime & 0x01)) Delay = (unsigned short)ROMAddr[0x225]; + else Delay = (unsigned short)ROMAddr[0x226]; + } + } } SiS_ShortDelay(SiS_Pr, Delay); @@ -520,23 +522,23 @@ SiS_PanelDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DelayTime) #ifdef SIS315H - if((HwInfo->jChipType >= SIS_661) || - (HwInfo->jChipType <= SIS_315PRO) || - (HwInfo->jChipType == SIS_330) || + if((SiS_Pr->ChipType >= SIS_661) || + (SiS_Pr->ChipType <= SIS_315PRO) || + (SiS_Pr->ChipType == SIS_330) || (SiS_Pr->SiS_ROMNew)) { - if(!(DelayTime & 0x01)) { + if(!(DelayTime & 0x01)) { SiS_DDC2Delay(SiS_Pr, 0x1000); - } else { + } else { SiS_DDC2Delay(SiS_Pr, 0x4000); - } + } } else if((SiS_Pr->SiS_IF_DEF_LVDS == 1) /* || - (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || + (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || (SiS_Pr->SiS_CustomT == CUT_CLEVO1400) */ ) { /* 315 series, LVDS; Special */ - if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { - PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); + if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { + PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); if(SiS_Pr->SiS_CustomT == CUT_CLEVO1400) { if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1b) & 0x10)) PanelID = 0x12; } @@ -546,35 +548,35 @@ SiS_PanelDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DelayTime) DelayIndex = PanelID >> 4; } if((DelayTime >= 2) && ((PanelID & 0x0f) == 1)) { - Delay = 3; - } else { - if(DelayTime >= 2) DelayTime -= 2; - if(!(DelayTime & 0x01)) { - Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[0]; - } else { - Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[1]; - } + Delay = 3; + } else { + if(DelayTime >= 2) DelayTime -= 2; + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[1]; + } if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { - if(ROMAddr[0x13c] & 0x40) { - if(!(DelayTime & 0x01)) { - Delay = (USHORT)ROMAddr[0x17e]; - } else { - Delay = (USHORT)ROMAddr[0x17f]; - } - } - } - } + if(ROMAddr[0x13c] & 0x40) { + if(!(DelayTime & 0x01)) { + Delay = (unsigned short)ROMAddr[0x17e]; + } else { + Delay = (unsigned short)ROMAddr[0x17f]; + } + } + } + } SiS_ShortDelay(SiS_Pr, Delay); } } else if(SiS_Pr->SiS_VBType & VB_SISVB) { /* 315 series, all bridges */ DelayIndex = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4; - if(!(DelayTime & 0x01)) { - Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0]; - } else { - Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; - } + if(!(DelayTime & 0x01)) { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0]; + } else { + Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; + } Delay <<= 8; SiS_DDC2Delay(SiS_Pr, Delay); @@ -587,12 +589,11 @@ SiS_PanelDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DelayTime) #ifdef SIS315H static void -SiS_PanelDelayLoop(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT DelayTime, USHORT DelayLoop) +SiS_PanelDelayLoop(struct SiS_Private *SiS_Pr, unsigned short DelayTime, unsigned short DelayLoop) { int i; - for(i=0; i<DelayLoop; i++) { - SiS_PanelDelay(SiS_Pr, HwInfo, DelayTime); + for(i = 0; i < DelayLoop; i++) { + SiS_PanelDelay(SiS_Pr, DelayTime); } } #endif @@ -602,86 +603,86 @@ SiS_PanelDelayLoop(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, /*********************************************/ void -SiS_WaitRetrace1(SiS_Private *SiS_Pr) +SiS_WaitRetrace1(struct SiS_Private *SiS_Pr) { - USHORT watchdog; + unsigned short watchdog; - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return; - if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x17) & 0x80)) return; + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return; + if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x17) & 0x80)) return; - watchdog = 65535; - while((SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08) && --watchdog); - watchdog = 65535; - while((!(SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog); + watchdog = 65535; + while((SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08) && --watchdog); + watchdog = 65535; + while((!(SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog); } #if defined(SIS300) || defined(SIS315H) static void -SiS_WaitRetrace2(SiS_Private *SiS_Pr, USHORT reg) +SiS_WaitRetrace2(struct SiS_Private *SiS_Pr, unsigned short reg) { - USHORT watchdog; + unsigned short watchdog; - watchdog = 65535; - while((SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02) && --watchdog); - watchdog = 65535; - while((!(SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02)) && --watchdog); + watchdog = 65535; + while((SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02) && --watchdog); + watchdog = 65535; + while((!(SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02)) && --watchdog); } #endif static void -SiS_WaitVBRetrace(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_WaitVBRetrace(struct SiS_Private *SiS_Pr) { - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return; - } - if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x80)) { - SiS_WaitRetrace1(SiS_Pr); - } else { - SiS_WaitRetrace2(SiS_Pr, 0x25); - } + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return; + } + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x80)) { + SiS_WaitRetrace1(SiS_Pr); + } else { + SiS_WaitRetrace2(SiS_Pr, 0x25); + } #endif - } else { + } else { #ifdef SIS315H - if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) { - SiS_WaitRetrace1(SiS_Pr); - } else { - SiS_WaitRetrace2(SiS_Pr, 0x30); - } + if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) { + SiS_WaitRetrace1(SiS_Pr); + } else { + SiS_WaitRetrace2(SiS_Pr, 0x30); + } #endif - } + } } static void -SiS_VBWait(SiS_Private *SiS_Pr) +SiS_VBWait(struct SiS_Private *SiS_Pr) { - USHORT tempal,temp,i,j; + unsigned short tempal,temp,i,j; - temp = 0; - for(i=0; i<3; i++) { - for(j=0; j<100; j++) { - tempal = SiS_GetRegByte(SiS_Pr->SiS_P3da); - if(temp & 0x01) { - if((tempal & 0x08)) continue; - else break; - } else { - if(!(tempal & 0x08)) continue; - else break; - } - } - temp ^= 0x01; - } + temp = 0; + for(i = 0; i < 3; i++) { + for(j = 0; j < 100; j++) { + tempal = SiS_GetRegByte(SiS_Pr->SiS_P3da); + if(temp & 0x01) { + if((tempal & 0x08)) continue; + else break; + } else { + if(!(tempal & 0x08)) continue; + else break; + } + } + temp ^= 0x01; + } } static void -SiS_VBLongWait(SiS_Private *SiS_Pr) +SiS_VBLongWait(struct SiS_Private *SiS_Pr) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - SiS_VBWait(SiS_Pr); - } else { - SiS_WaitRetrace1(SiS_Pr); - } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_VBWait(SiS_Pr); + } else { + SiS_WaitRetrace1(SiS_Pr); + } } /*********************************************/ @@ -690,237 +691,225 @@ SiS_VBLongWait(SiS_Private *SiS_Pr) #ifdef SIS300 static BOOLEAN -SiS_Is301B(SiS_Private *SiS_Pr) +SiS_Is301B(struct SiS_Private *SiS_Pr) { - if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01) >= 0xb0) return TRUE; - return FALSE; + if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01) >= 0xb0) return TRUE; + return FALSE; } #endif static BOOLEAN -SiS_CRT2IsLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_CRT2IsLCD(struct SiS_Private *SiS_Pr) { - USHORT flag; - - if(HwInfo->jChipType == SIS_730) { - flag = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13); - if(flag & 0x20) return TRUE; - } - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - if(flag & 0x20) return TRUE; - return FALSE; + if(SiS_Pr->ChipType == SIS_730) { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x20) return TRUE; + } + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & 0x20) return TRUE; + return FALSE; } BOOLEAN -SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_IsDualEdge(struct SiS_Private *SiS_Pr) { #ifdef SIS315H - USHORT flag; - - if(HwInfo->jChipType >= SIS_315H) { - if((HwInfo->jChipType != SIS_650) || (SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0)) { - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if(flag & EnableDualEdge) return TRUE; - } - } + if(SiS_Pr->ChipType >= SIS_315H) { + if((SiS_Pr->ChipType != SIS_650) || (SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0)) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableDualEdge) return TRUE; + } + } #endif - return FALSE; + return FALSE; } BOOLEAN -SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_IsVAMode(struct SiS_Private *SiS_Pr) { #ifdef SIS315H - USHORT flag; + unsigned short flag; - if(HwInfo->jChipType >= SIS_315H) { - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if((flag & EnableDualEdge) && (flag & SetToLCDA)) return TRUE; - } + if(SiS_Pr->ChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if((flag & EnableDualEdge) && (flag & SetToLCDA)) return TRUE; + } #endif - return FALSE; + return FALSE; } #ifdef SIS315H static BOOLEAN -SiS_IsVAorLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_IsVAorLCD(struct SiS_Private *SiS_Pr) { - if(SiS_IsVAMode(SiS_Pr,HwInfo)) return TRUE; - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) return TRUE; - return FALSE; + if(SiS_IsVAMode(SiS_Pr)) return TRUE; + if(SiS_CRT2IsLCD(SiS_Pr)) return TRUE; + return FALSE; } #endif static BOOLEAN -SiS_IsDualLink(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_IsDualLink(struct SiS_Private *SiS_Pr) { #ifdef SIS315H - if(HwInfo->jChipType >= SIS_315H) { - if((SiS_CRT2IsLCD(SiS_Pr, HwInfo)) || - (SiS_IsVAMode(SiS_Pr, HwInfo))) { - if(SiS_Pr->SiS_LCDInfo & LCDDualLink) return TRUE; - } - } + if(SiS_Pr->ChipType >= SIS_315H) { + if((SiS_CRT2IsLCD(SiS_Pr)) || + (SiS_IsVAMode(SiS_Pr))) { + if(SiS_Pr->SiS_LCDInfo & LCDDualLink) return TRUE; + } + } #endif - return FALSE; + return FALSE; } #ifdef SIS315H static BOOLEAN -SiS_TVEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_TVEnabled(struct SiS_Private *SiS_Pr) { - if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) != 0x0c) return TRUE; - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS301LV302LV)) { - if(SiS_GetReg(SiS_Pr->SiS_Part2Port,0x4d) & 0x10) return TRUE; - } - return FALSE; + if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) != 0x0c) return TRUE; + if(SiS_Pr->SiS_VBType & VB_SISYPBPR) { + if(SiS_GetReg(SiS_Pr->SiS_Part2Port,0x4d) & 0x10) return TRUE; + } + return FALSE; } #endif #ifdef SIS315H static BOOLEAN -SiS_LCDAEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_LCDAEnabled(struct SiS_Private *SiS_Pr) { - if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) return TRUE; - return FALSE; + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) return TRUE; + return FALSE; } #endif #ifdef SIS315H static BOOLEAN -SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_WeHaveBacklightCtrl(struct SiS_Private *SiS_Pr) { - if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) { - if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0x10) return TRUE; - } - return FALSE; + if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0x10) return TRUE; + } + return FALSE; } #endif #ifdef SIS315H static BOOLEAN -SiS_IsNotM650orLater(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_IsNotM650orLater(struct SiS_Private *SiS_Pr) { - USHORT flag; + unsigned short flag; - if(HwInfo->jChipType == SIS_650) { - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f); - flag &= 0xF0; - /* Check for revision != A0 only */ - if((flag == 0xe0) || (flag == 0xc0) || - (flag == 0xb0) || (flag == 0x90)) return FALSE; - } else if(HwInfo->jChipType >= SIS_661) return FALSE; - return TRUE; + if(SiS_Pr->ChipType == SIS_650) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0; + /* Check for revision != A0 only */ + if((flag == 0xe0) || (flag == 0xc0) || + (flag == 0xb0) || (flag == 0x90)) return FALSE; + } else if(SiS_Pr->ChipType >= SIS_661) return FALSE; + return TRUE; } #endif #ifdef SIS315H static BOOLEAN -SiS_IsYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_IsYPbPr(struct SiS_Private *SiS_Pr) { - USHORT flag; - - if(HwInfo->jChipType >= SIS_315H) { - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if(flag & EnableCHYPbPr) return TRUE; /* = YPrPb = 0x08 */ - } - return FALSE; + if(SiS_Pr->ChipType >= SIS_315H) { + /* YPrPb = 0x08 */ + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableCHYPbPr) return TRUE; + } + return FALSE; } #endif #ifdef SIS315H static BOOLEAN -SiS_IsChScart(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_IsChScart(struct SiS_Private *SiS_Pr) { - USHORT flag; - - if(HwInfo->jChipType >= SIS_315H) { - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if(flag & EnableCHScart) return TRUE; /* = Scart = 0x04 */ - } - return FALSE; + if(SiS_Pr->ChipType >= SIS_315H) { + /* Scart = 0x04 */ + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableCHScart) return TRUE; + } + return FALSE; } #endif #ifdef SIS315H static BOOLEAN -SiS_IsTVOrYPbPrOrScart(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_IsTVOrYPbPrOrScart(struct SiS_Private *SiS_Pr) { - USHORT flag; + unsigned short flag; - if(HwInfo->jChipType >= SIS_315H) { - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - if(flag & SetCRT2ToTV) return TRUE; - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if(flag & EnableCHYPbPr) return TRUE; /* = YPrPb = 0x08 */ - if(flag & EnableCHScart) return TRUE; /* = Scart = 0x04 - TW */ - } else { - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - if(flag & SetCRT2ToTV) return TRUE; - } - return FALSE; + if(SiS_Pr->ChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToTV) return TRUE; + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & EnableCHYPbPr) return TRUE; /* = YPrPb = 0x08 */ + if(flag & EnableCHScart) return TRUE; /* = Scart = 0x04 - TW */ + } else { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToTV) return TRUE; + } + return FALSE; } #endif #ifdef SIS315H static BOOLEAN -SiS_IsLCDOrLCDA(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_IsLCDOrLCDA(struct SiS_Private *SiS_Pr) { - USHORT flag; + unsigned short flag; - if(HwInfo->jChipType >= SIS_315H) { - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - if(flag & SetCRT2ToLCD) return TRUE; - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if(flag & SetToLCDA) return TRUE; - } else { - flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - if(flag & SetCRT2ToLCD) return TRUE; - } - return FALSE; + if(SiS_Pr->ChipType >= SIS_315H) { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToLCD) return TRUE; + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(flag & SetToLCDA) return TRUE; + } else { + flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(flag & SetCRT2ToLCD) return TRUE; + } + return FALSE; } #endif static BOOLEAN -SiS_BridgeIsOn(SiS_Private *SiS_Pr) +SiS_HaveBridge(struct SiS_Private *SiS_Pr) { - USHORT flag; + unsigned short flag; - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - return TRUE; - } else if(SiS_Pr->SiS_VBType & VB_SISVB) { - flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); - if((flag == 1) || (flag == 2)) return TRUE; - } - return FALSE; + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + return TRUE; + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); + if((flag == 1) || (flag == 2)) return TRUE; + } + return FALSE; } static BOOLEAN -SiS_BridgeIsEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_BridgeIsEnabled(struct SiS_Private *SiS_Pr) { - USHORT flag; + unsigned short flag; - if(SiS_BridgeIsOn(SiS_Pr)) { - flag = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); - if(HwInfo->jChipType < SIS_315H) { - flag &= 0xa0; - if((flag == 0x80) || (flag == 0x20)) return TRUE; - } else { - flag &= 0x50; - if((flag == 0x40) || (flag == 0x10)) return TRUE; - } - } - return FALSE; + if(SiS_HaveBridge(SiS_Pr)) { + flag = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + if(SiS_Pr->ChipType < SIS_315H) { + flag &= 0xa0; + if((flag == 0x80) || (flag == 0x20)) return TRUE; + } else { + flag &= 0x50; + if((flag == 0x40) || (flag == 0x10)) return TRUE; + } + } + return FALSE; } static BOOLEAN -SiS_BridgeInSlavemode(SiS_Private *SiS_Pr) +SiS_BridgeInSlavemode(struct SiS_Private *SiS_Pr) { - USHORT flag1; + unsigned short flag1; - flag1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31); - if(flag1 & (SetInSlaveMode >> 8)) return TRUE; - return FALSE; + flag1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31); + if(flag1 & (SetInSlaveMode >> 8)) return TRUE; + return FALSE; } /*********************************************/ @@ -928,119 +917,97 @@ SiS_BridgeInSlavemode(SiS_Private *SiS_Pr) /*********************************************/ /* Setup general purpose IO for Chrontel communication */ +#ifdef SIS300 void -SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo) +SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo) { - unsigned long acpibase; + unsigned int acpibase; unsigned short temp; if(!(SiS_Pr->SiS_ChSW)) return; -#ifdef LINUX_KERNEL - SiS_SetRegLong(0xcf8,0x80000874); /* get ACPI base */ - acpibase = SiS_GetRegLong(0xcfc); +#ifdef SIS_LINUX_KERNEL + acpibase = sisfb_read_lpc_pci_dword(SiS_Pr, 0x74); #else acpibase = pciReadLong(0x00000800, 0x74); #endif acpibase &= 0xFFFF; - temp = SiS_GetRegShort((USHORT)(acpibase + 0x3c)); /* ACPI register 0x3c: GP Event 1 I/O mode select */ + if(!acpibase) return; + temp = SiS_GetRegShort((acpibase + 0x3c)); /* ACPI register 0x3c: GP Event 1 I/O mode select */ temp &= 0xFEFF; - SiS_SetRegShort((USHORT)(acpibase + 0x3c), temp); - temp = SiS_GetRegShort((USHORT)(acpibase + 0x3c)); - temp = SiS_GetRegShort((USHORT)(acpibase + 0x3a)); /* ACPI register 0x3a: GP Pin Level (low/high) */ + SiS_SetRegShort((acpibase + 0x3c), temp); + temp = SiS_GetRegShort((acpibase + 0x3c)); + temp = SiS_GetRegShort((acpibase + 0x3a)); /* ACPI register 0x3a: GP Pin Level (low/high) */ temp &= 0xFEFF; if(!(myvbinfo & SetCRT2ToTV)) temp |= 0x0100; - SiS_SetRegShort((USHORT)(acpibase + 0x3a), temp); - temp = SiS_GetRegShort((USHORT)(acpibase + 0x3a)); + SiS_SetRegShort((acpibase + 0x3a), temp); + temp = SiS_GetRegShort((acpibase + 0x3a)); } +#endif void -SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo, int checkcrt2mode) +SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, int checkcrt2mode) { - USHORT tempax,tempbx,temp; - USHORT modeflag, resinfo=0; + unsigned short tempax, tempbx, temp; + unsigned short modeflag, resinfo = 0; - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; - } + SiS_Pr->SiS_SetFlag = 0; - SiS_Pr->SiS_SetFlag = 0; + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); - SiS_Pr->SiS_ModeType = modeflag & ModeTypeMask; + SiS_Pr->SiS_ModeType = modeflag & ModeTypeMask; - tempbx = 0; - if(SiS_BridgeIsOn(SiS_Pr)) { - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); -#if 0 - if(HwInfo->jChipType < SIS_661) { - /* NO - YPbPr not set yet ! */ - if(SiS_Pr->SiS_YPbPr & <all ypbpr except 525i>) { - temp &= (SetCRT2ToHiVision | SwitchCRT2 | SetSimuScanMode); /* 0x83 */ - temp |= SetCRT2ToHiVision; /* 0x80 */ - } - if(SiS_Pr->SiS_YPbPr & <ypbpr525i>) { - temp &= (SetCRT2ToHiVision | SwitchCRT2 | SetSimuScanMode); /* 0x83 */ - temp |= SetCRT2ToSVIDEO; /* 0x08 */ - } - } -#endif - tempbx |= temp; - tempax = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) << 8; - tempax &= (DriverMode | LoadDACFlag | SetNotSimuMode | SetPALTV); - tempbx |= tempax; + if((ModeNo > 0x13) && (!SiS_Pr->UseCustomMode)) { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + tempbx = 0; + + if(SiS_HaveBridge(SiS_Pr)) { + + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + tempbx |= temp; + tempax = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) << 8; + tempax &= (DriverMode | LoadDACFlag | SetNotSimuMode | SetPALTV); + tempbx |= tempax; #ifdef SIS315H - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_VBType & VB_SISLCDA) { + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISLCDA) { if(ModeNo == 0x03) { - /* Mode 0x03 is never in driver mode */ + /* Mode 0x03 is never in driver mode */ SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x31,0xbf); } if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8))) { - /* Reset LCDA setting if not driver mode */ + /* Reset LCDA setting if not driver mode */ SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); } if(IS_SIS650) { - if(SiS_Pr->SiS_UseLCDA) { + if(SiS_Pr->SiS_UseLCDA) { if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xF0) { if((ModeNo <= 0x13) || (!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8)))) { - SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x38,(EnableDualEdge | SetToLCDA)); + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x38,(EnableDualEdge | SetToLCDA)); } } } } temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if((temp & (EnableDualEdge | SetToLCDA)) == (EnableDualEdge | SetToLCDA)) { - tempbx |= SetCRT2ToLCDA; + if((temp & (EnableDualEdge | SetToLCDA)) == (EnableDualEdge | SetToLCDA)) { + tempbx |= SetCRT2ToLCDA; } } - if(SiS_Pr->SiS_VBType & (VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)) { - tempbx &= ~(SetCRT2ToRAMDAC); - } - - if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->ChipType >= SIS_661) { /* New CR layout */ tempbx &= ~(SetCRT2ToYPbPr525750 | SetCRT2ToHiVision); - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if(SiS_Pr->SiS_VBType & VB_SISYPBPR) { - if(temp & 0x04) { - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; - if(temp == 0x60) tempbx |= SetCRT2ToHiVision; - else tempbx |= SetCRT2ToYPbPr525750; - } - } else if(SiS_Pr->SiS_VBType & VB_SISHIVISION) { - if(temp & 0x04) { - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; - if(temp == 0x60) tempbx |= SetCRT2ToHiVision; + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & 0x04) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; + if(temp == 0x60) tempbx |= SetCRT2ToHiVision; + else if(SiS_Pr->SiS_VBType & VB_SISYPBPR) { + tempbx |= SetCRT2ToYPbPr525750; } } - } + } if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); @@ -1048,7 +1015,7 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, tempbx |= SetCRT2ToLCDA; } if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(temp & EnableCHYPbPr) { + if(temp & EnableCHYPbPr) { tempbx |= SetCRT2ToCHYPbPr; } } @@ -1057,44 +1024,49 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, #endif /* SIS315H */ - if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(!(SiS_Pr->SiS_VBType & VB_SISVGA2)) { + tempbx &= ~(SetCRT2ToRAMDAC); + } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { temp = SetCRT2ToSVIDEO | - SetCRT2ToAVIDEO | - SetCRT2ToSCART | - SetCRT2ToLCDA | - SetCRT2ToLCD | - SetCRT2ToRAMDAC | - SetCRT2ToHiVision | + SetCRT2ToAVIDEO | + SetCRT2ToSCART | + SetCRT2ToLCDA | + SetCRT2ToLCD | + SetCRT2ToRAMDAC | + SetCRT2ToHiVision | SetCRT2ToYPbPr525750; - } else { - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - temp = SetCRT2ToAVIDEO | + } else { + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + temp = SetCRT2ToAVIDEO | SetCRT2ToSVIDEO | SetCRT2ToSCART | SetCRT2ToLCDA | SetCRT2ToLCD | SetCRT2ToCHYPbPr; - } else { - temp = SetCRT2ToLCDA | + } else { + temp = SetCRT2ToLCDA | SetCRT2ToLCD; } } else { - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - temp = SetCRT2ToTV | SetCRT2ToLCD; - } else { - temp = SetCRT2ToLCD; + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + temp = SetCRT2ToTV | SetCRT2ToLCD; + } else { + temp = SetCRT2ToLCD; } } - } + } + + if(!(tempbx & temp)) { + tempax = DisableCRT2Display; + tempbx = 0; + } - if(!(tempbx & temp)) { - tempax = DisableCRT2Display; - tempbx = 0; - } + if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBType & VB_SISVB) { - USHORT clearmask = ( DriverMode | + unsigned short clearmask = ( DriverMode | DisableCRT2Display | LoadDACFlag | SetNotSimuMode | @@ -1102,106 +1074,104 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SetPALTV | SwitchCRT2 | SetSimuScanMode ); - if(tempbx & SetCRT2ToLCDA) tempbx &= (clearmask | SetCRT2ToLCDA); + + if(tempbx & SetCRT2ToLCDA) tempbx &= (clearmask | SetCRT2ToLCDA); if(tempbx & SetCRT2ToRAMDAC) tempbx &= (clearmask | SetCRT2ToRAMDAC); if(tempbx & SetCRT2ToLCD) tempbx &= (clearmask | SetCRT2ToLCD); if(tempbx & SetCRT2ToSCART) tempbx &= (clearmask | SetCRT2ToSCART); if(tempbx & SetCRT2ToHiVision) tempbx &= (clearmask | SetCRT2ToHiVision); if(tempbx & SetCRT2ToYPbPr525750) tempbx &= (clearmask | SetCRT2ToYPbPr525750); - } else { - if(HwInfo->jChipType >= SIS_315H) { + + } else { + + if(SiS_Pr->ChipType >= SIS_315H) { if(tempbx & SetCRT2ToLCDA) { - tempbx &= (0xFF00|SwitchCRT2|SetSimuScanMode); + tempbx &= (0xFF00|SwitchCRT2|SetSimuScanMode); } } - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(tempbx & SetCRT2ToTV) { - tempbx &= (0xFF00|SetCRT2ToTV|SwitchCRT2|SetSimuScanMode); + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(tempbx & SetCRT2ToTV) { + tempbx &= (0xFF00|SetCRT2ToTV|SwitchCRT2|SetSimuScanMode); } - } - if(tempbx & SetCRT2ToLCD) { - tempbx &= (0xFF00|SetCRT2ToLCD|SwitchCRT2|SetSimuScanMode); } - if(HwInfo->jChipType >= SIS_315H) { + if(tempbx & SetCRT2ToLCD) { + tempbx &= (0xFF00|SetCRT2ToLCD|SwitchCRT2|SetSimuScanMode); + } + if(SiS_Pr->ChipType >= SIS_315H) { if(tempbx & SetCRT2ToLCDA) { tempbx |= SetCRT2ToLCD; } } + } - if(tempax & DisableCRT2Display) { - if(!(tempbx & (SwitchCRT2 | SetSimuScanMode))) { - tempbx = SetSimuScanMode | DisableCRT2Display; - } - } + if(tempax & DisableCRT2Display) { + if(!(tempbx & (SwitchCRT2 | SetSimuScanMode))) { + tempbx = SetSimuScanMode | DisableCRT2Display; + } + } - if(!(tempbx & DriverMode)) tempbx |= SetSimuScanMode; + if(!(tempbx & DriverMode)) tempbx |= SetSimuScanMode; /* LVDS/CHRONTEL (LCD/TV) and 301BDH (LCD) can only be slave in 8bpp modes */ if(SiS_Pr->SiS_ModeType <= ModeVGA) { if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) || ((SiS_Pr->SiS_VBType & VB_NoLCD) && (tempbx & SetCRT2ToLCD)) ) { - modeflag &= (~CRT2Mode); + modeflag &= (~CRT2Mode); } } - if(!(tempbx & SetSimuScanMode)) { - if(tempbx & SwitchCRT2) { - if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) { - if( (HwInfo->jChipType >= SIS_315H) && - (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) { - if(resinfo != SIS_RI_1600x1200) { - tempbx |= SetSimuScanMode; - } - } else { - tempbx |= SetSimuScanMode; - } + if(!(tempbx & SetSimuScanMode)) { + if(tempbx & SwitchCRT2) { + if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) { + if(resinfo != SIS_RI_1600x1200) { + tempbx |= SetSimuScanMode; + } } - } else { - if(SiS_BridgeIsEnabled(SiS_Pr,HwInfo)) { - if(!(tempbx & DriverMode)) { - if(SiS_BridgeInSlavemode(SiS_Pr)) { + } else { + if(SiS_BridgeIsEnabled(SiS_Pr)) { + if(!(tempbx & DriverMode)) { + if(SiS_BridgeInSlavemode(SiS_Pr)) { tempbx |= SetSimuScanMode; - } - } - } - } - } - - if(!(tempbx & DisableCRT2Display)) { - if(tempbx & DriverMode) { - if(tempbx & SetSimuScanMode) { - if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) { - if( (HwInfo->jChipType >= SIS_315H) && - (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) { - if(resinfo != SIS_RI_1600x1200) { - tempbx |= SetInSlaveMode; - } - } else { - tempbx |= SetInSlaveMode; - } - } - } - } else { - tempbx |= SetInSlaveMode; - } - } + } + } + } + } + } - } + if(!(tempbx & DisableCRT2Display)) { + if(tempbx & DriverMode) { + if(tempbx & SetSimuScanMode) { + if((!(modeflag & CRT2Mode)) && (checkcrt2mode)) { + if(resinfo != SIS_RI_1600x1200) { + tempbx |= SetInSlaveMode; + } + } + } + } else { + tempbx |= SetInSlaveMode; + } + } - SiS_Pr->SiS_VBInfo = tempbx; + } - if(HwInfo->jChipType == SIS_630) { - SiS_SetChrontelGPIO(SiS_Pr, SiS_Pr->SiS_VBInfo); - } + SiS_Pr->SiS_VBInfo = tempbx; -#ifdef TWDEBUG -#ifdef LINUX_KERNEL - printk(KERN_DEBUG "sisfb: (VBInfo= 0x%04x, SetFlag=0x%04x)\n", +#ifdef SIS300 + if(SiS_Pr->ChipType == SIS_630) { + SiS_SetChrontelGPIO(SiS_Pr, SiS_Pr->SiS_VBInfo); + } +#endif + +#ifdef SIS_LINUX_KERNEL +#if 0 + printk(KERN_DEBUG "sisfb: (init301: VBInfo= 0x%04x, SetFlag=0x%04x)\n", SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag); #endif -#ifdef LINUX_XF86 - xf86DrvMsgVerb(0, X_PROBED, 3, "(init301: VBInfo=0x%04x, SetFlag=0x%04x)\n", +#endif +#ifdef SIS_XORG_XF86 +#ifdef TWDEBUG + xf86DrvMsg(0, X_PROBED, "(init301: VBInfo=0x%04x, SetFlag=0x%04x)\n", SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag); #endif #endif @@ -1212,41 +1182,41 @@ SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ void -SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_SetYPbPr(struct SiS_Private *SiS_Pr) { - UCHAR temp; + unsigned char temp; - /* Note: This variable is only used on 30xLV systems. - * CR38 has a different meaning on LVDS/CH7019 systems. - * On 661 and later, these bits moved to CR35. - * - * On 301, 301B, only HiVision 1080i is supported. - * On 30xLV, 301C, only YPbPr 1080i is supported. - */ + /* Note: This variable is only used on 30xLV systems. + * CR38 has a different meaning on LVDS/CH7019 systems. + * On 661 and later, these bits moved to CR35. + * + * On 301, 301B, only HiVision 1080i is supported. + * On 30xLV, 301C, only YPbPr 1080i is supported. + */ - SiS_Pr->SiS_YPbPr = 0; - if(HwInfo->jChipType >= SIS_661) return; + SiS_Pr->SiS_YPbPr = 0; + if(SiS_Pr->ChipType >= SIS_661) return; - if(SiS_Pr->SiS_VBType) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - SiS_Pr->SiS_YPbPr = YPbPrHiVision; - } - } + if(SiS_Pr->SiS_VBType) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + SiS_Pr->SiS_YPbPr = YPbPrHiVision; + } + } - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_VBType & (VB_SIS301LV302LV | VB_SIS301C)) { - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if(temp & 0x08) { - switch((temp >> 4)) { - case 0x00: SiS_Pr->SiS_YPbPr = YPbPr525i; break; - case 0x01: SiS_Pr->SiS_YPbPr = YPbPr525p; break; - case 0x02: SiS_Pr->SiS_YPbPr = YPbPr750p; break; - case 0x03: SiS_Pr->SiS_YPbPr = YPbPrHiVision; break; - } - } - } - } + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISYPBPR) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(temp & 0x08) { + switch((temp >> 4)) { + case 0x00: SiS_Pr->SiS_YPbPr = YPbPr525i; break; + case 0x01: SiS_Pr->SiS_YPbPr = YPbPr525p; break; + case 0x02: SiS_Pr->SiS_YPbPr = YPbPr750p; break; + case 0x03: SiS_Pr->SiS_YPbPr = YPbPrHiVision; break; + } + } + } + } } @@ -1255,199 +1225,204 @@ SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /*********************************************/ void -SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo) +SiS_SetTVMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT temp, temp1, resinfo = 0, romindex = 0; - UCHAR OutputSelect = *SiS_Pr->pSiS_OutputSelect; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short temp, temp1, resinfo = 0, romindex = 0; + unsigned char OutputSelect = *SiS_Pr->pSiS_OutputSelect; - SiS_Pr->SiS_TVMode = 0; + SiS_Pr->SiS_TVMode = 0; - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return; - if(SiS_Pr->UseCustomMode) return; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return; + if(SiS_Pr->UseCustomMode) return; - if(ModeNo > 0x13) { - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; - } + if(ModeNo > 0x13) { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } - if(HwInfo->jChipType < SIS_661) { + if(SiS_Pr->ChipType < SIS_661) { - if(SiS_Pr->SiS_VBInfo & SetPALTV) SiS_Pr->SiS_TVMode |= TVSetPAL; + if(SiS_Pr->SiS_VBInfo & SetPALTV) SiS_Pr->SiS_TVMode |= TVSetPAL; - if(SiS_Pr->SiS_VBType & VB_SISVB) { - temp = 0; - if((HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730)) { - temp = 0x35; - romindex = 0xfe; - } else if(HwInfo->jChipType >= SIS_315H) { - temp = 0x38; - romindex = 0xf3; - if(HwInfo->jChipType >= SIS_330) romindex = 0x11b; - } - if(temp) { - if(romindex && SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { - OutputSelect = ROMAddr[romindex]; - if(!(OutputSelect & EnablePALMN)) { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,temp,0x3F); - } - } - temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,temp); - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - if(temp1 & EnablePALM) { /* 0x40 */ - SiS_Pr->SiS_TVMode |= TVSetPALM; - SiS_Pr->SiS_TVMode &= ~TVSetPAL; - } else if(temp1 & EnablePALN) { /* 0x80 */ - SiS_Pr->SiS_TVMode |= TVSetPALN; - } - } else { - if(temp1 & EnableNTSCJ) { /* 0x40 */ - SiS_Pr->SiS_TVMode |= TVSetNTSCJ; - } - } - } - /* Translate HiVision/YPbPr to our new flags */ - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if(SiS_Pr->SiS_YPbPr == YPbPr750p) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p; - else if(SiS_Pr->SiS_YPbPr == YPbPr525p) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p; - else if(SiS_Pr->SiS_YPbPr == YPbPrHiVision) SiS_Pr->SiS_TVMode |= TVSetHiVision; - else SiS_Pr->SiS_TVMode |= TVSetYPbPr525i; - if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetYPbPr525p | TVSetYPbPr525i)) { - SiS_Pr->SiS_VBInfo &= ~SetCRT2ToHiVision; - SiS_Pr->SiS_VBInfo |= SetCRT2ToYPbPr525750; - } else if(SiS_Pr->SiS_TVMode & TVSetHiVision) { - SiS_Pr->SiS_TVMode |= TVSetPAL; - } - } - } else if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(SiS_Pr->SiS_CHOverScan) { - if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); - if((temp & TVOverScan) || (SiS_Pr->SiS_CHOverScan == 1)) { - SiS_Pr->SiS_TVMode |= TVSetCHOverScan; - } - } else if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x79); - if((temp & 0x80) || (SiS_Pr->SiS_CHOverScan == 1)) { - SiS_Pr->SiS_TVMode |= TVSetCHOverScan; - } - } - if(SiS_Pr->SiS_CHSOverScan) { - SiS_Pr->SiS_TVMode |= TVSetCHOverScan; - } - } - if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - if(temp & EnablePALM) SiS_Pr->SiS_TVMode |= TVSetPALM; - else if(temp & EnablePALN) SiS_Pr->SiS_TVMode |= TVSetPALN; - } else { - if(temp & EnableNTSCJ) { - SiS_Pr->SiS_TVMode |= TVSetNTSCJ; - } - } - } - } + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = 0; + if((SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730)) { + temp = 0x35; + romindex = 0xfe; + } else if(SiS_Pr->ChipType >= SIS_315H) { + temp = 0x38; + if(SiS_Pr->ChipType < XGI_20) { + romindex = 0xf3; + if(SiS_Pr->ChipType >= SIS_330) romindex = 0x11b; + } + } + if(temp) { + if(romindex && SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { + OutputSelect = ROMAddr[romindex]; + if(!(OutputSelect & EnablePALMN)) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,temp,0x3F); + } + } + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,temp); + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + if(temp1 & EnablePALM) { /* 0x40 */ + SiS_Pr->SiS_TVMode |= TVSetPALM; + SiS_Pr->SiS_TVMode &= ~TVSetPAL; + } else if(temp1 & EnablePALN) { /* 0x80 */ + SiS_Pr->SiS_TVMode |= TVSetPALN; + } + } else { + if(temp1 & EnableNTSCJ) { /* 0x40 */ + SiS_Pr->SiS_TVMode |= TVSetNTSCJ; + } + } + } + /* Translate HiVision/YPbPr to our new flags */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(SiS_Pr->SiS_YPbPr == YPbPr750p) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p; + else if(SiS_Pr->SiS_YPbPr == YPbPr525p) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p; + else if(SiS_Pr->SiS_YPbPr == YPbPrHiVision) SiS_Pr->SiS_TVMode |= TVSetHiVision; + else SiS_Pr->SiS_TVMode |= TVSetYPbPr525i; + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetYPbPr525p | TVSetYPbPr525i)) { + SiS_Pr->SiS_VBInfo &= ~SetCRT2ToHiVision; + SiS_Pr->SiS_VBInfo |= SetCRT2ToYPbPr525750; + } else if(SiS_Pr->SiS_TVMode & TVSetHiVision) { + SiS_Pr->SiS_TVMode |= TVSetPAL; + } + } + } else if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_CHOverScan) { + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + if((temp & TVOverScan) || (SiS_Pr->SiS_CHOverScan == 1)) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } else if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x79); + if((temp & 0x80) || (SiS_Pr->SiS_CHOverScan == 1)) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } + if(SiS_Pr->SiS_CHSOverScan) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + if(temp & EnablePALM) SiS_Pr->SiS_TVMode |= TVSetPALM; + else if(temp & EnablePALN) SiS_Pr->SiS_TVMode |= TVSetPALN; + } else { + if(temp & EnableNTSCJ) { + SiS_Pr->SiS_TVMode |= TVSetNTSCJ; + } + } + } + } - } else { /* 661 and later */ + } else { /* 661 and later */ - temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); - if(temp1 & 0x01) { - SiS_Pr->SiS_TVMode |= TVSetPAL; - if(temp1 & 0x08) { - SiS_Pr->SiS_TVMode |= TVSetPALN; - } else if(temp1 & 0x04) { - if(SiS_Pr->SiS_VBType & VB_SISVB) { - SiS_Pr->SiS_TVMode &= ~TVSetPAL; - } - SiS_Pr->SiS_TVMode |= TVSetPALM; - } - } else { - if(temp1 & 0x02) { - SiS_Pr->SiS_TVMode |= TVSetNTSCJ; - } - } - if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - if(SiS_Pr->SiS_CHOverScan) { - if((temp1 & 0x10) || (SiS_Pr->SiS_CHOverScan == 1)) { - SiS_Pr->SiS_TVMode |= TVSetCHOverScan; - } - } - } - if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - temp1 &= 0xe0; - if(temp1 == 0x00) SiS_Pr->SiS_TVMode |= TVSetYPbPr525i; - else if(temp1 == 0x20) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p; - else if(temp1 == 0x40) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p; - } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - SiS_Pr->SiS_TVMode |= (TVSetHiVision | TVSetPAL); - } - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750 | SetCRT2ToHiVision)) { - if(resinfo == SIS_RI_800x480 || resinfo == SIS_RI_1024x576 || resinfo == SIS_RI_1280x720) { - SiS_Pr->SiS_TVMode |= TVAspect169; - } else { - temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x39); - if(temp1 & 0x02) { - if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetHiVision)) { - SiS_Pr->SiS_TVMode |= TVAspect169; - } else { - SiS_Pr->SiS_TVMode |= TVAspect43LB; - } - } else { - SiS_Pr->SiS_TVMode |= TVAspect43; - } - } - } - } - } + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + if(temp1 & 0x01) { + SiS_Pr->SiS_TVMode |= TVSetPAL; + if(temp1 & 0x08) { + SiS_Pr->SiS_TVMode |= TVSetPALN; + } else if(temp1 & 0x04) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_Pr->SiS_TVMode &= ~TVSetPAL; + } + SiS_Pr->SiS_TVMode |= TVSetPALM; + } + } else { + if(temp1 & 0x02) { + SiS_Pr->SiS_TVMode |= TVSetNTSCJ; + } + } + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_Pr->SiS_CHOverScan) { + if((temp1 & 0x10) || (SiS_Pr->SiS_CHOverScan == 1)) { + SiS_Pr->SiS_TVMode |= TVSetCHOverScan; + } + } + } + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + temp1 &= 0xe0; + if(temp1 == 0x00) SiS_Pr->SiS_TVMode |= TVSetYPbPr525i; + else if(temp1 == 0x20) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p; + else if(temp1 == 0x40) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p; + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + SiS_Pr->SiS_TVMode |= (TVSetHiVision | TVSetPAL); + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750 | SetCRT2ToHiVision)) { + if(resinfo == SIS_RI_800x480 || resinfo == SIS_RI_1024x576 || resinfo == SIS_RI_1280x720) { + SiS_Pr->SiS_TVMode |= TVAspect169; + } else { + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x39); + if(temp1 & 0x02) { + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetHiVision)) { + SiS_Pr->SiS_TVMode |= TVAspect169; + } else { + SiS_Pr->SiS_TVMode |= TVAspect43LB; + } + } else { + SiS_Pr->SiS_TVMode |= TVAspect43; + } + } + } + } + } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART) SiS_Pr->SiS_TVMode |= TVSetPAL; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART) SiS_Pr->SiS_TVMode |= TVSetPAL; - if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - SiS_Pr->SiS_TVMode |= TVSetPAL; - SiS_Pr->SiS_TVMode &= ~(TVSetPALM | TVSetPALN | TVSetNTSCJ); - } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525i | TVSetYPbPr525p | TVSetYPbPr750p)) { - SiS_Pr->SiS_TVMode &= ~(TVSetPAL | TVSetNTSCJ | TVSetPALM | TVSetPALN); - } - } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + SiS_Pr->SiS_TVMode |= TVSetPAL; + SiS_Pr->SiS_TVMode &= ~(TVSetPALM | TVSetPALN | TVSetNTSCJ); + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525i | TVSetYPbPr525p | TVSetYPbPr750p)) { + SiS_Pr->SiS_TVMode &= ~(TVSetPAL | TVSetNTSCJ | TVSetPALM | TVSetPALN); + } + } - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { - SiS_Pr->SiS_TVMode |= TVSetTVSimuMode; - } - } + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + SiS_Pr->SiS_TVMode |= TVSetTVSimuMode; + } + } - if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { - /* BIOS sets TVNTSC1024 without checking 525p here. Wrong? */ - if(!(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr525p | TVSetYPbPr750p))) { - if(resinfo == SIS_RI_1024x768) { - SiS_Pr->SiS_TVMode |= TVSetNTSC1024; - } - } - } + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + if(resinfo == SIS_RI_1024x768) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { + SiS_Pr->SiS_TVMode |= TVSet525p1024; + } else if(!(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr750p))) { + SiS_Pr->SiS_TVMode |= TVSetNTSC1024; + } + } + } - SiS_Pr->SiS_TVMode |= TVRPLLDIV2XO; - if((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) && - (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; - } else if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) { - SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; - } else if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) { - if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { - SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; - } - } + SiS_Pr->SiS_TVMode |= TVRPLLDIV2XO; + if((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) && + (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; + } else if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) { + SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; + } else if(!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) { + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + SiS_Pr->SiS_TVMode &= ~TVRPLLDIV2XO; + } + } - } + } - SiS_Pr->SiS_VBInfo &= ~SetPALTV; + SiS_Pr->SiS_VBInfo &= ~SetPALTV; +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "(init301: TVMode %x, VBInfo %x)\n", SiS_Pr->SiS_TVMode, SiS_Pr->SiS_VBInfo); + xf86DrvMsg(0, X_INFO, "(init301: TVMode %x, VBInfo %x)\n", SiS_Pr->SiS_TVMode, SiS_Pr->SiS_VBInfo); +#endif #endif } @@ -1455,41 +1430,46 @@ SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_IN /* GET LCD INFO */ /*********************************************/ -static USHORT -SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr) +static unsigned short +SiS_GetBIOSLCDResInfo(struct SiS_Private *SiS_Pr) { - USHORT temp = SiS_Pr->SiS_LCDResInfo; + unsigned short temp = SiS_Pr->SiS_LCDResInfo; /* Translate my LCDResInfo to BIOS value */ - if(temp == Panel_1280x768_2) temp = Panel_1280x768; - if(temp == Panel_1280x800_2) temp = Panel_1280x800; + switch(temp) { + case Panel_1280x768_2: temp = Panel_1280x768; break; + case Panel_1280x800_2: temp = Panel_1280x800; break; + case Panel_1280x854: temp = Panel661_1280x854; break; + } return temp; } static void -SiS_GetLCDInfoBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_GetLCDInfoBIOS(struct SiS_Private *SiS_Pr) { #ifdef SIS315H - UCHAR *ROMAddr; - USHORT temp; + unsigned char *ROMAddr; + unsigned short temp; +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "Paneldata driver: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n", - SiS_Pr->PanelHT, SiS_Pr->PanelVT, + SiS_Pr->PanelHT, SiS_Pr->PanelVT, SiS_Pr->PanelHRS, SiS_Pr->PanelHRE, SiS_Pr->PanelVRS, SiS_Pr->PanelVRE, SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK, SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A, SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B); +#endif #endif - if((ROMAddr = GetLCDStructPtr661(SiS_Pr, HwInfo))) { + if((ROMAddr = GetLCDStructPtr661(SiS_Pr))) { if((temp = SISGETROMW(6)) != SiS_Pr->PanelHT) { - SiS_Pr->SiS_NeedRomModeData = TRUE; + SiS_Pr->SiS_NeedRomModeData = TRUE; SiS_Pr->PanelHT = temp; } if((temp = SISGETROMW(8)) != SiS_Pr->PanelVT) { - SiS_Pr->SiS_NeedRomModeData = TRUE; - SiS_Pr->PanelVT = temp; + SiS_Pr->SiS_NeedRomModeData = TRUE; + SiS_Pr->PanelVT = temp; } SiS_Pr->PanelHRS = SISGETROMW(10); SiS_Pr->PanelHRE = SISGETROMW(12); @@ -1497,20 +1477,22 @@ SiS_GetLCDInfoBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_Pr->PanelVRE = SISGETROMW(16); SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315; SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].CLOCK = - SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].CLOCK = (USHORT)((UCHAR)ROMAddr[18]); + SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].CLOCK = (unsigned short)((unsigned char)ROMAddr[18]); SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2B = SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_A = ROMAddr[19]; SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2C = SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_B = ROMAddr[20]; +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "Paneldata BIOS: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n", - SiS_Pr->PanelHT, SiS_Pr->PanelVT, + SiS_Pr->PanelHT, SiS_Pr->PanelVT, SiS_Pr->PanelHRS, SiS_Pr->PanelHRE, SiS_Pr->PanelVRS, SiS_Pr->PanelVRE, SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK, SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A, SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B); +#endif #endif } @@ -1518,35 +1500,35 @@ SiS_GetLCDInfoBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } static void -SiS_CheckScaling(SiS_Private *SiS_Pr, USHORT resinfo, const UCHAR *nonscalingmodes) -{ - int i = 0; - while(nonscalingmodes[i] != 0xff) { - if(nonscalingmodes[i++] == resinfo) { - if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) || - (SiS_Pr->UsePanelScaler == -1)) { - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - } - break; - } - } +SiS_CheckScaling(struct SiS_Private *SiS_Pr, unsigned short resinfo, + const unsigned char *nonscalingmodes) +{ + int i = 0; + while(nonscalingmodes[i] != 0xff) { + if(nonscalingmodes[i++] == resinfo) { + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) || + (SiS_Pr->UsePanelScaler == -1)) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + } } void -SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo) +SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { + unsigned short temp,modeflag,resinfo=0,modexres=0,modeyres=0; + BOOLEAN panelcanscale = FALSE; #ifdef SIS300 - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - const unsigned char SiS300SeriesLCDRes[] = + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + static const unsigned char SiS300SeriesLCDRes[] = { 0, 1, 2, 3, 7, 4, 5, 8, 0, 0, 10, 0, 0, 0, 0, 15 }; #endif #ifdef SIS315H - UCHAR *myptr = NULL; + unsigned char *myptr = NULL; #endif - USHORT temp,modeflag,resinfo=0,modexres=0,modeyres=0; - BOOLEAN panelcanscale = FALSE; SiS_Pr->SiS_LCDResInfo = 0; SiS_Pr->SiS_LCDTypeInfo = 0; @@ -1557,14 +1539,14 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_Pr->PanelVRE = 999; /* VSync end */ SiS_Pr->SiS_NeedRomModeData = FALSE; + /* Alternative 1600x1200@60 timing for 1600x1200 LCDA */ + SiS_Pr->Alternate1600x1200 = FALSE; + if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) return; - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); + + if((ModeNo > 0x13) && (!SiS_Pr->UseCustomMode)) { resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; modexres = SiS_Pr->SiS_ModeResInfo[resinfo].HTotal; modeyres = SiS_Pr->SiS_ModeResInfo[resinfo].VTotal; @@ -1575,16 +1557,16 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /* For broken BIOSes: Assume 1024x768 */ if(temp == 0) temp = 0x02; - if((HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { + if((SiS_Pr->ChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { SiS_Pr->SiS_LCDTypeInfo = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x7c) >> 2; - } else if((HwInfo->jChipType < SIS_315H) || (HwInfo->jChipType >= SIS_661)) { + } else if((SiS_Pr->ChipType < SIS_315H) || (SiS_Pr->ChipType >= SIS_661)) { SiS_Pr->SiS_LCDTypeInfo = temp >> 4; } else { SiS_Pr->SiS_LCDTypeInfo = (temp & 0x0F) - 1; } temp &= 0x0f; #ifdef SIS300 - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { /* Very old BIOSes only know 7 sizes (NetVista 2179, 1.01g) */ if(SiS_Pr->SiS_VBType & VB_SIS301) { if(temp < 0x0f) temp &= 0x07; @@ -1595,17 +1577,22 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, #endif /* Translate to our internal types */ - if(HwInfo->jChipType == SIS_550) { - if(temp == Panel310_640x480_2) temp = Panel_640x480_2; - if(temp == Panel310_640x480_3) temp = Panel_640x480_3; +#ifdef SIS315H + if(SiS_Pr->ChipType == SIS_550) { + if (temp == Panel310_1152x768) temp = Panel_320x240_2; /* Verified working */ + else if(temp == Panel310_320x240_2) temp = Panel_320x240_2; + else if(temp == Panel310_320x240_3) temp = Panel_320x240_3; + } else if(SiS_Pr->ChipType >= SIS_661) { + if(temp == Panel661_1280x854) temp = Panel_1280x854; } +#endif - if(SiS_Pr->SiS_VBType & VB_SISLVDS) { /* SiS LVDS */ + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { /* SiS LVDS */ if(temp == Panel310_1280x768) { temp = Panel_1280x768_2; } if(SiS_Pr->SiS_ROMNew) { - if(temp == Panel661_1280x800) { + if(temp == Panel661_1280x800) { temp = Panel_1280x800_2; } } @@ -1613,13 +1600,17 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_Pr->SiS_LCDResInfo = temp; +#ifdef SIS300 if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { - SiS_Pr->SiS_LCDResInfo = Panel_Barco1366; + SiS_Pr->SiS_LCDResInfo = Panel_Barco1366; } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { - SiS_Pr->SiS_LCDResInfo = Panel_848x480; + SiS_Pr->SiS_LCDResInfo = Panel_848x480; + } else if(SiS_Pr->SiS_CustomT == CUT_PANEL856) { + SiS_Pr->SiS_LCDResInfo = Panel_856x480; } } +#endif if(SiS_Pr->SiS_VBType & VB_SISVB) { if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301) @@ -1633,10 +1624,16 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_Pr->SiS_LCDInfo = temp & ~0x000e; /* Need temp below! */ - /* These can't scale no matter what */ + /* These must/can't scale no matter what */ switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_320x240_1: + case Panel_320x240_2: + case Panel_320x240_3: case Panel_1280x960: SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD; + break; + case Panel_640x480: + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; } panelcanscale = (SiS_Pr->SiS_LCDInfo & DontExpandLCD) ? TRUE : FALSE; @@ -1646,41 +1643,41 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /* Dual link, Pass 1:1 BIOS default, etc. */ #ifdef SIS315H - if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->ChipType >= SIS_661) { if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - if(temp & 0x08) SiS_Pr->SiS_LCDInfo |= LCDPass11; + if(temp & 0x08) SiS_Pr->SiS_LCDInfo |= LCDPass11; } - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - if(SiS_Pr->SiS_ROMNew) { + if(SiS_Pr->SiS_VBType & VB_SISDUALLINK) { + if(SiS_Pr->SiS_ROMNew) { if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink; - } else if((myptr = GetLCDStructPtr661(SiS_Pr, HwInfo))) { - if(myptr[2] & 0x01) SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } else if((myptr = GetLCDStructPtr661(SiS_Pr))) { + if(myptr[2] & 0x01) SiS_Pr->SiS_LCDInfo |= LCDDualLink; } } - } else if(HwInfo->jChipType >= SIS_315H) { + } else if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x01) SiS_Pr->SiS_LCDInfo |= LCDPass11; + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x01) SiS_Pr->SiS_LCDInfo |= LCDPass11; } if((SiS_Pr->SiS_ROMNew) && (!(SiS_Pr->PanelSelfDetected))) { - SiS_Pr->SiS_LCDInfo &= ~(LCDRGB18Bit); + SiS_Pr->SiS_LCDInfo &= ~(LCDRGB18Bit); temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); - if(temp & 0x01) SiS_Pr->SiS_LCDInfo |= LCDRGB18Bit; - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if(temp & 0x01) SiS_Pr->SiS_LCDInfo |= LCDRGB18Bit; + if(SiS_Pr->SiS_VBType & VB_SISDUALLINK) { if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink; } } else if(!(SiS_Pr->SiS_ROMNew)) { - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - if((SiS_Pr->SiS_CustomT == CUT_CLEVO1024) && + if(SiS_Pr->SiS_VBType & VB_SISDUALLINK) { + if((SiS_Pr->SiS_CustomT == CUT_CLEVO1024) && (SiS_Pr->SiS_LCDResInfo == Panel_1024x768)) { SiS_Pr->SiS_LCDInfo |= LCDDualLink; } - if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || - (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) || (SiS_Pr->SiS_LCDResInfo == Panel_1680x1050)) { SiS_Pr->SiS_LCDInfo |= LCDDualLink; } - } + } } } #endif @@ -1691,12 +1688,12 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_Pr->SiS_LCDInfo &= ~LCDPass11; } else if(SiS_Pr->SiS_VBType & VB_SISVB) { if(SiS_Pr->SiS_VBType & VB_SISLVDS) { - /* Always center screen on SiS LVDS (if scaling is disabled) */ - SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + /* Always center screen on SiS LVDS (if scaling is disabled) */ + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; } else { - /* By default, pass 1:1 on SiS TMDS (if scaling is supported) */ - if(panelcanscale) SiS_Pr->SiS_LCDInfo |= LCDPass11; - if(SiS_Pr->CenterScreen == 1) SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + /* By default, pass 1:1 on SiS TMDS (if scaling is supported) */ + if(panelcanscale) SiS_Pr->SiS_LCDInfo |= LCDPass11; + if(SiS_Pr->CenterScreen == 1) SiS_Pr->SiS_LCDInfo &= ~LCDPass11; } } @@ -1704,19 +1701,15 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; switch(SiS_Pr->SiS_LCDResInfo) { - case Panel_320x480: SiS_Pr->PanelXRes = 320; SiS_Pr->PanelYRes = 480; - SiS_Pr->PanelHT = 400; SiS_Pr->PanelVT = 525; - SiS_Pr->PanelVCLKIdx300 = VCLK28; - SiS_Pr->PanelVCLKIdx315 = VCLK28; - break; - case Panel_640x480_2: - case Panel_640x480_3: SiS_Pr->PanelXRes = 640; SiS_Pr->PanelYRes = 480; - SiS_Pr->PanelVRS = 24; SiS_Pr->PanelVRE = 3; + case Panel_320x240_1: + case Panel_320x240_2: + case Panel_320x240_3: SiS_Pr->PanelXRes = 640; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelVRS = 24; SiS_Pr->PanelVRE = 3; SiS_Pr->PanelVCLKIdx300 = VCLK28; SiS_Pr->PanelVCLKIdx315 = VCLK28; break; case Panel_640x480: SiS_Pr->PanelXRes = 640; SiS_Pr->PanelYRes = 480; - SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVRE = 3; SiS_Pr->PanelVCLKIdx300 = VCLK28; SiS_Pr->PanelVCLKIdx315 = VCLK28; break; @@ -1728,52 +1721,52 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_Pr->PanelVCLKIdx315 = VCLK40; break; case Panel_1024x600: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 600; - SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 800; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 800; SiS_Pr->PanelHRS = 24; SiS_Pr->PanelHRE = 136; SiS_Pr->PanelVRS = 2 /* 88 */ ; SiS_Pr->PanelVRE = 6; - SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; SiS_Pr->PanelVCLKIdx315 = VCLK65_315; - break; + break; case Panel_1024x768: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 768; - SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; SiS_Pr->PanelHRS = 24; SiS_Pr->PanelHRE = 136; SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { SiS_Pr->PanelHRS = 23; - SiS_Pr->PanelVRE = 5; + SiS_Pr->PanelVRE = 5; } SiS_Pr->PanelVCLKIdx300 = VCLK65_300; SiS_Pr->PanelVCLKIdx315 = VCLK65_315; - SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + SiS_GetLCDInfoBIOS(SiS_Pr); break; case Panel_1152x768: SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes = 768; - SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; - SiS_Pr->PanelHRS = 24; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHRS = 24; SiS_Pr->PanelHRE = 136; SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { SiS_Pr->PanelHRS = 23; - SiS_Pr->PanelVRE = 5; + SiS_Pr->PanelVRE = 5; } - SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; SiS_Pr->PanelVCLKIdx315 = VCLK65_315; - break; + break; case Panel_1152x864: SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes = 864; - break; + break; case Panel_1280x720: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 720; - SiS_Pr->PanelHT = 1650; SiS_Pr->PanelVT = 750; + SiS_Pr->PanelHT = 1650; SiS_Pr->PanelVT = 750; SiS_Pr->PanelHRS = 110; SiS_Pr->PanelHRE = 40; SiS_Pr->PanelVRS = 5; SiS_Pr->PanelVRE = 5; SiS_Pr->PanelVCLKIdx315 = VCLK_1280x720; /* Data above for TMDS (projector); get from BIOS for LVDS */ - SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + SiS_GetLCDInfoBIOS(SiS_Pr); break; case Panel_1280x768: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 768; - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { SiS_Pr->PanelHT = 1408; SiS_Pr->PanelVT = 806; SiS_Pr->PanelVCLKIdx300 = VCLK81_300; /* ? */ SiS_Pr->PanelVCLKIdx315 = VCLK81_315; /* ? */ } else { - SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 802; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 802; SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRS = 112; SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; SiS_Pr->PanelVCLKIdx300 = VCLK81_300; @@ -1781,77 +1774,100 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } break; case Panel_1280x768_2: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 768; - SiS_Pr->PanelHT = 1660; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHT = 1660; SiS_Pr->PanelVT = 806; SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; SiS_Pr->PanelVCLKIdx315 = VCLK_1280x768_2; - SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + SiS_GetLCDInfoBIOS(SiS_Pr); break; case Panel_1280x800: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 800; - SiS_Pr->PanelHT = 1408; SiS_Pr->PanelVT = 816; + SiS_Pr->PanelHT = 1408; SiS_Pr->PanelVT = 816; SiS_Pr->PanelHRS = 21; SiS_Pr->PanelHRE = 24; SiS_Pr->PanelVRS = 4; SiS_Pr->PanelVRE = 3; SiS_Pr->PanelVCLKIdx315 = VCLK_1280x800_315; - SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + SiS_GetLCDInfoBIOS(SiS_Pr); break; case Panel_1280x800_2: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 800; - SiS_Pr->PanelHT = 1552; SiS_Pr->PanelVT = 812; + SiS_Pr->PanelHT = 1552; SiS_Pr->PanelVT = 812; SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; SiS_Pr->PanelVRS = 4; SiS_Pr->PanelVRE = 3; SiS_Pr->PanelVCLKIdx315 = VCLK_1280x800_315_2; - SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + SiS_GetLCDInfoBIOS(SiS_Pr); + break; + case Panel_1280x854: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 854; + SiS_Pr->PanelHT = 1664; SiS_Pr->PanelVT = 861; + SiS_Pr->PanelHRS = 16; SiS_Pr->PanelHRE = 112; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x854; + SiS_GetLCDInfoBIOS(SiS_Pr); break; case Panel_1280x960: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 960; - SiS_Pr->PanelHT = 1800; SiS_Pr->PanelVT = 1000; + SiS_Pr->PanelHT = 1800; SiS_Pr->PanelVT = 1000; SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300; SiS_Pr->PanelVCLKIdx315 = VCLK108_3_315; - if(resinfo == SIS_RI_1280x1024) { + if(resinfo == SIS_RI_1280x1024) { SiS_Pr->PanelVCLKIdx300 = VCLK100_300; SiS_Pr->PanelVCLKIdx315 = VCLK100_315; } break; case Panel_1280x1024: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 1024; - SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300; SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; - SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + SiS_GetLCDInfoBIOS(SiS_Pr); break; case Panel_1400x1050: SiS_Pr->PanelXRes = 1400; SiS_Pr->PanelYRes = 1050; - SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; - SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; /* HRE OK for LVDS, not for LCDA */ + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; - SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + SiS_GetLCDInfoBIOS(SiS_Pr); break; case Panel_1600x1200: SiS_Pr->PanelXRes = 1600; SiS_Pr->PanelYRes = 1200; - SiS_Pr->PanelHT = 2160; SiS_Pr->PanelVT = 1250; + SiS_Pr->PanelHT = 2160; SiS_Pr->PanelVT = 1250; SiS_Pr->PanelHRS = 64; SiS_Pr->PanelHRE = 192; SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; SiS_Pr->PanelVCLKIdx315 = VCLK162_315; - SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + if(SiS_Pr->SiS_VBType & VB_SISTMDSLCDA) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_Pr->PanelHT = 1760; SiS_Pr->PanelVT = 1235; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 32; + SiS_Pr->PanelVRS = 2; SiS_Pr->PanelVRE = 4; + SiS_Pr->PanelVCLKIdx315 = VCLK130_315; + SiS_Pr->Alternate1600x1200 = TRUE; + } + } else if(SiS_Pr->SiS_IF_DEF_LVDS) { + SiS_Pr->PanelHT = 2048; SiS_Pr->PanelVT = 1320; + SiS_Pr->PanelHRS = SiS_Pr->PanelHRE = 999; + SiS_Pr->PanelVRS = SiS_Pr->PanelVRE = 999; + } + SiS_GetLCDInfoBIOS(SiS_Pr); break; case Panel_1680x1050: SiS_Pr->PanelXRes = 1680; SiS_Pr->PanelYRes = 1050; - SiS_Pr->PanelHT = 1900; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHT = 1900; SiS_Pr->PanelVT = 1066; SiS_Pr->PanelHRS = 26; SiS_Pr->PanelHRE = 76; SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; SiS_Pr->PanelVCLKIdx315 = VCLK121_315; - SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + SiS_GetLCDInfoBIOS(SiS_Pr); break; case Panel_Barco1366: SiS_Pr->PanelXRes = 1360; SiS_Pr->PanelYRes = 1024; - SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; - break; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + break; case Panel_848x480: SiS_Pr->PanelXRes = 848; SiS_Pr->PanelYRes = 480; - SiS_Pr->PanelHT = 1088; SiS_Pr->PanelVT = 525; - break; + SiS_Pr->PanelHT = 1088; SiS_Pr->PanelVT = 525; + break; + case Panel_856x480: SiS_Pr->PanelXRes = 856; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelHT = 1088; SiS_Pr->PanelVT = 525; + break; case Panel_Custom: SiS_Pr->PanelXRes = SiS_Pr->CP_MaxX; - SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY; + SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY; SiS_Pr->PanelHT = SiS_Pr->CHTotal; SiS_Pr->PanelVT = SiS_Pr->CVTotal; if(SiS_Pr->CP_PreferredIndex != -1) { SiS_Pr->PanelXRes = SiS_Pr->CP_HDisplay[SiS_Pr->CP_PreferredIndex]; - SiS_Pr->PanelYRes = SiS_Pr->CP_VDisplay[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelYRes = SiS_Pr->CP_VDisplay[SiS_Pr->CP_PreferredIndex]; SiS_Pr->PanelHT = SiS_Pr->CP_HTotal[SiS_Pr->CP_PreferredIndex]; SiS_Pr->PanelVT = SiS_Pr->CP_VTotal[SiS_Pr->CP_PreferredIndex]; SiS_Pr->PanelHRS = SiS_Pr->CP_HSyncStart[SiS_Pr->CP_PreferredIndex]; @@ -1863,22 +1879,22 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_Pr->PanelVRS -= SiS_Pr->PanelYRes; SiS_Pr->PanelVRE -= SiS_Pr->PanelVRS; if(SiS_Pr->CP_PrefClock) { - int idx; - SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315; + int idx; + SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315; SiS_Pr->PanelVCLKIdx300 = VCLK_CUSTOM_300; - if(HwInfo->jChipType < SIS_315H) idx = VCLK_CUSTOM_300; + if(SiS_Pr->ChipType < SIS_315H) idx = VCLK_CUSTOM_300; else idx = VCLK_CUSTOM_315; - SiS_Pr->SiS_VCLKData[idx].CLOCK = - SiS_Pr->SiS_VBVCLKData[idx].CLOCK = SiS_Pr->CP_PrefClock; - SiS_Pr->SiS_VCLKData[idx].SR2B = - SiS_Pr->SiS_VBVCLKData[idx].Part4_A = SiS_Pr->CP_PrefSR2B; - SiS_Pr->SiS_VCLKData[idx].SR2C = - SiS_Pr->SiS_VBVCLKData[idx].Part4_B = SiS_Pr->CP_PrefSR2C; + SiS_Pr->SiS_VCLKData[idx].CLOCK = + SiS_Pr->SiS_VBVCLKData[idx].CLOCK = SiS_Pr->CP_PrefClock; + SiS_Pr->SiS_VCLKData[idx].SR2B = + SiS_Pr->SiS_VBVCLKData[idx].Part4_A = SiS_Pr->CP_PrefSR2B; + SiS_Pr->SiS_VCLKData[idx].SR2C = + SiS_Pr->SiS_VBVCLKData[idx].Part4_B = SiS_Pr->CP_PrefSR2C; } } break; default: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 768; - SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; break; } @@ -1887,14 +1903,16 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, (SiS_Pr->SiS_IF_DEF_DSTN) || (SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || - (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) { + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + (SiS_Pr->SiS_CustomT == CUT_PANEL856) ) { SiS_Pr->PanelHRS = 999; SiS_Pr->PanelHRE = 999; } if( (SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || - (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) { + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + (SiS_Pr->SiS_CustomT == CUT_PANEL856) ) { SiS_Pr->PanelVRS = 999; SiS_Pr->PanelVRE = 999; } @@ -1912,18 +1930,18 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, case Panel_Custom: case Panel_1152x864: case Panel_1280x768: /* TMDS only */ - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; break; case Panel_800x600: { - static const UCHAR nonscalingmodes[] = { + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, 0xff }; SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); break; } case Panel_1024x768: { - static const UCHAR nonscalingmodes[] = { + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, 0xff @@ -1932,7 +1950,7 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, break; } case Panel_1280x720: { - static const UCHAR nonscalingmodes[] = { + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, 0xff @@ -1944,7 +1962,7 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, break; } case Panel_1280x768_2: { /* LVDS only */ - static const UCHAR nonscalingmodes[] = { + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, SIS_RI_1152x768,0xff @@ -1952,23 +1970,23 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); switch(resinfo) { case SIS_RI_1280x720: if(SiS_Pr->UsePanelScaler == -1) { - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - } - break; + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; } - break; + break; } case Panel_1280x800: { /* SiS TMDS special (Averatec 6200 series) */ - static const UCHAR nonscalingmodes[] = { + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, SIS_RI_1152x768,SIS_RI_1280x720,SIS_RI_1280x768,0xff }; SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); - break; + break; } case Panel_1280x800_2: { /* SiS LVDS */ - static const UCHAR nonscalingmodes[] = { + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, SIS_RI_1152x768,0xff @@ -1977,66 +1995,83 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, switch(resinfo) { case SIS_RI_1280x720: case SIS_RI_1280x768: if(SiS_Pr->UsePanelScaler == -1) { - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - } - break; + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; } - break; + break; } - case Panel_1280x960: { - static const UCHAR nonscalingmodes[] = { + case Panel_1280x854: { /* SiS LVDS */ + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, - SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800, - 0xff + SIS_RI_1152x768,0xff }; SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); - break; - } - case Panel_1280x1024: { - static const UCHAR nonscalingmodes[] = { + switch(resinfo) { + case SIS_RI_1280x720: + case SIS_RI_1280x768: + case SIS_RI_1280x800: if(SiS_Pr->UsePanelScaler == -1) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + } + break; + } + case Panel_1280x960: { + static const unsigned char nonscalingmodes[] = { + SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, + SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800, + SIS_RI_1280x854,0xff + }; + SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); + break; + } + case Panel_1280x1024: { + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800, - SIS_RI_1280x960,0xff + SIS_RI_1280x854,SIS_RI_1280x960,0xff }; SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); break; } case Panel_1400x1050: { - static const UCHAR nonscalingmodes[] = { + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, - SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x768,SIS_RI_1280x800,SIS_RI_1280x960, - 0xff + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x768,SIS_RI_1280x800,SIS_RI_1280x854, + SIS_RI_1280x960,0xff }; SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); - switch(resinfo) { + switch(resinfo) { case SIS_RI_1280x720: if(SiS_Pr->UsePanelScaler == -1) { - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - } - break; + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; case SIS_RI_1280x1024: SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - break; + break; } break; } case Panel_1600x1200: { - static const UCHAR nonscalingmodes[] = { + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x720,SIS_RI_1280x768,SIS_RI_1280x800, - SIS_RI_1280x960,SIS_RI_1360x768,SIS_RI_1360x1024,0xff + SIS_RI_1280x854,SIS_RI_1280x960,SIS_RI_1360x768,SIS_RI_1360x1024,0xff }; SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); - break; + break; } case Panel_1680x1050: { - static const UCHAR nonscalingmodes[] = { + static const unsigned char nonscalingmodes[] = { SIS_RI_720x480, SIS_RI_720x576, SIS_RI_768x576, SIS_RI_800x480, SIS_RI_848x480, SIS_RI_856x480, SIS_RI_960x540, SIS_RI_960x600, SIS_RI_1024x576,SIS_RI_1024x600, - SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x960,SIS_RI_1360x768,SIS_RI_1360x1024, - 0xff + SIS_RI_1152x768,SIS_RI_1152x864,SIS_RI_1280x854,SIS_RI_1280x960,SIS_RI_1360x768, + SIS_RI_1360x1024,0xff }; SiS_CheckScaling(SiS_Pr, resinfo, nonscalingmodes); break; @@ -2044,25 +2079,25 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } } +#ifdef SIS300 if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { - SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20; /* neg h/v sync, RGB24(D0 = 0) */ + if(SiS_Pr->SiS_CustomT == CUT_PANEL848 || SiS_Pr->SiS_CustomT == CUT_PANEL856) { + SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20; /* neg h/v sync, RGB24(D0 = 0) */ } } -#ifdef SIS300 - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { - if(!(ROMAddr[0x235] & 0x02)) { - SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); - } + if(!(ROMAddr[0x235] & 0x02)) { + SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); + } } - } - } else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + } + } else if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { if((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10))) { - SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); + SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); } } } @@ -2080,7 +2115,7 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, switch(SiS_Pr->SiS_LCDResInfo) { case Panel_640x480: - SiS_Pr->SiS_LCDInfo |= LCDPass11; + SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11); break; case Panel_1280x800: /* Don't pass 1:1 by default (TMDS special) */ @@ -2097,7 +2132,7 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, break; } - if(SiS_Pr->UseCustomMode) { + if((SiS_Pr->UseCustomMode) || (SiS_Pr->SiS_CustomT == CUT_UNKNOWNLCD)) { SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11); } @@ -2107,19 +2142,19 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } /* LVDS DDA */ - if(!((HwInfo->jChipType < SIS_315H) && (SiS_Pr->SiS_SetFlag & SetDOSMode))) { + if(!((SiS_Pr->ChipType < SIS_315H) && (SiS_Pr->SiS_SetFlag & SetDOSMode))) { if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) { if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) { if(ModeNo == 0x12) { if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; } } else if(ModeNo > 0x13) { if(SiS_Pr->SiS_LCDResInfo == Panel_1024x600) { - if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { - if((resinfo == SIS_RI_800x600) || (resinfo == SIS_RI_400x300)) { - SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + if((resinfo == SIS_RI_800x600) || (resinfo == SIS_RI_400x300)) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; } } } @@ -2128,18 +2163,18 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } if(modeflag & HalfDCLK) { - if(SiS_Pr->SiS_IF_DEF_TRUMPION == 1) { + if(SiS_Pr->SiS_IF_DEF_TRUMPION == 1) { SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; - } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; } else if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) { SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; } else if(ModeNo > 0x13) { - if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { - if(resinfo == SIS_RI_512x384) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; - } else if(SiS_Pr->SiS_LCDResInfo == Panel_800x600) { - if(resinfo == SIS_RI_400x300) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; - } + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(resinfo == SIS_RI_512x384) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_800x600) { + if(resinfo == SIS_RI_400x300) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } } } @@ -2148,21 +2183,21 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /* VESA timing */ if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { if(SiS_Pr->SiS_VBInfo & SetNotSimuMode) { - SiS_Pr->SiS_SetFlag |= LCDVESATiming; + SiS_Pr->SiS_SetFlag |= LCDVESATiming; } } else { SiS_Pr->SiS_SetFlag |= LCDVESATiming; } -#ifdef LINUX_KERNEL -#ifdef TWDEBUG +#ifdef SIS_LINUX_KERNEL +#if 0 printk(KERN_DEBUG "sisfb: (LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n", SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo); #endif #endif -#ifdef LINUX_XF86 +#ifdef SIS_XORG_XF86 xf86DrvMsgVerb(0, X_PROBED, 4, - "(init301: LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x SetFlag=0x%04x)\n", + "(init301: LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x SetFlag=0x%04x)\n", SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo, SiS_Pr->SiS_SetFlag); #endif } @@ -2171,45 +2206,46 @@ SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /* GET VCLK */ /*********************************************/ -USHORT -SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +unsigned short +SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { - USHORT CRT2Index,VCLKIndex=0,VCLKIndexGEN=0; - USHORT modeflag,resinfo,tempbx; - const UCHAR *CHTVVCLKPtr = NULL; + unsigned short CRT2Index, VCLKIndex = 0, VCLKIndexGEN = 0, VCLKIndexGENCRT = 0; + unsigned short modeflag, resinfo, tempbx; + const unsigned char *CHTVVCLKPtr = NULL; if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; VCLKIndexGEN = (SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)) >> 2) & 0x03; + VCLKIndexGENCRT = VCLKIndexGEN; } else { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; VCLKIndexGEN = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; - if(HwInfo->jChipType < SIS_315H) VCLKIndexGEN &= 0x3f; + VCLKIndexGENCRT = SiS_GetRefCRTVCLK(SiS_Pr, RefreshRateTableIndex, + (SiS_Pr->SiS_SetFlag & ProgrammingCRT2) ? SiS_Pr->SiS_UseWideCRT2 : SiS_Pr->SiS_UseWide); } if(SiS_Pr->SiS_VBType & VB_SISVB) { /* 30x/B/LV */ if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { - CRT2Index >>= 6; - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /* LCD */ + CRT2Index >>= 6; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /* LCD */ - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { VCLKIndex = SiS_Pr->PanelVCLKIdx300; if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { - VCLKIndex = VCLKIndexGEN; + VCLKIndex = VCLKIndexGEN; } } else { VCLKIndex = SiS_Pr->PanelVCLKIdx315; if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { switch(resinfo) { - /* Only those whose IndexGEN doesn't match VBVCLK array */ - case SIS_RI_1280x720: VCLKIndex = VCLK_1280x720; break; + /* Correct those whose IndexGEN doesn't match VBVCLK array */ case SIS_RI_720x480: VCLKIndex = VCLK_720x480; break; case SIS_RI_720x576: VCLKIndex = VCLK_720x576; break; case SIS_RI_768x576: VCLKIndex = VCLK_768x576; break; @@ -2218,18 +2254,19 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, case SIS_RI_800x480: VCLKIndex = VCLK_800x480; break; case SIS_RI_1024x576: VCLKIndex = VCLK_1024x576; break; case SIS_RI_1152x864: VCLKIndex = VCLK_1152x864; break; + case SIS_RI_1280x720: VCLKIndex = VCLK_1280x720; break; case SIS_RI_1360x768: VCLKIndex = VCLK_1360x768; break; default: VCLKIndex = VCLKIndexGEN; } if(ModeNo <= 0x13) { - if(HwInfo->jChipType <= SIS_315PRO) { + if(SiS_Pr->ChipType <= SIS_315PRO) { if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x42; - } else { + } else { if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x00; } } - if(HwInfo->jChipType <= SIS_315PRO) { + if(SiS_Pr->ChipType <= SIS_315PRO) { if(VCLKIndex == 0) VCLKIndex = 0x41; if(VCLKIndex == 1) VCLKIndex = 0x43; if(VCLKIndex == 4) VCLKIndex = 0x44; @@ -2237,49 +2274,46 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } } - } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* TV */ + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* TV */ if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = HiTVVCLKDIV2; - else VCLKIndex = HiTVVCLK; - if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { - if(modeflag & Charx8Dot) VCLKIndex = HiTVSimuVCLK; - else VCLKIndex = HiTVTextVCLK; - } - } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) VCLKIndex = YPbPr750pVCLK; - else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) VCLKIndex = TVVCLKDIV2; - else if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = TVVCLKDIV2; - else VCLKIndex = TVVCLK; - - if(HwInfo->jChipType < SIS_315H) VCLKIndex += TVCLKBASE_300; - else VCLKIndex += TVCLKBASE_315; - - } else { /* VGA2 */ - - VCLKIndex = VCLKIndexGEN; - if(HwInfo->jChipType < SIS_315H) { - if(ModeNo > 0x13) { - if( (HwInfo->jChipType == SIS_630) && - (HwInfo->jChipRevision >= 0x30)) { + if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = HiTVVCLKDIV2; + else VCLKIndex = HiTVVCLK; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) VCLKIndex = HiTVSimuVCLK; + } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) VCLKIndex = YPbPr750pVCLK; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) VCLKIndex = TVVCLKDIV2; + else if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = TVVCLKDIV2; + else VCLKIndex = TVVCLK; + + if(SiS_Pr->ChipType < SIS_315H) VCLKIndex += TVCLKBASE_300; + else VCLKIndex += TVCLKBASE_315; + + } else { /* VGA2 */ + + VCLKIndex = VCLKIndexGENCRT; + if(SiS_Pr->ChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (SiS_Pr->ChipType == SIS_630) && + (SiS_Pr->ChipRevision >= 0x30)) { if(VCLKIndex == 0x14) VCLKIndex = 0x34; } /* Better VGA2 clock for 1280x1024@75 */ if(VCLKIndex == 0x17) VCLKIndex = 0x45; } - } - } + } + } } else { /* If not programming CRT2 */ - VCLKIndex = VCLKIndexGEN; - if(HwInfo->jChipType < SIS_315H) { - if(ModeNo > 0x13) { - if( (HwInfo->jChipType != SIS_630) && - (HwInfo->jChipType != SIS_300) ) { + VCLKIndex = VCLKIndexGENCRT; + if(SiS_Pr->ChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (SiS_Pr->ChipType != SIS_630) && + (SiS_Pr->ChipType != SIS_300) ) { if(VCLKIndex == 0x1b) VCLKIndex = 0x48; } } - } + } } } else { /* LVDS */ @@ -2288,12 +2322,12 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { - if( (SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) { + if( (SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) { VCLKIndex &= 0x1f; - tempbx = 0; + tempbx = 0; if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; - if(SiS_Pr->SiS_TVMode & TVSetPAL) { + if(SiS_Pr->SiS_TVMode & TVSetPAL) { tempbx += 2; if(SiS_Pr->SiS_ModeType > ModeVGA) { if(SiS_Pr->SiS_CHSOverScan) tempbx = 8; @@ -2306,66 +2340,68 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; } } - switch(tempbx) { - case 0: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUNTSC; break; - case 1: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKONTSC; break; - case 2: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPAL; break; - case 3: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL; break; + switch(tempbx) { + case 0: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUNTSC; break; + case 1: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKONTSC; break; + case 2: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPAL; break; + case 3: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL; break; case 4: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPALM; break; - case 5: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPALM; break; - case 6: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPALN; break; - case 7: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPALN; break; + case 5: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPALM; break; + case 6: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPALN; break; + case 7: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPALN; break; case 8: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKSOPAL; break; default: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL; break; - } - VCLKIndex = CHTVVCLKPtr[VCLKIndex]; + } + VCLKIndex = CHTVVCLKPtr[VCLKIndex]; - } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { VCLKIndex = SiS_Pr->PanelVCLKIdx300; } else { VCLKIndex = SiS_Pr->PanelVCLKIdx315; } +#ifdef SIS300 /* Special Timing: Barco iQ Pro R series */ if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) VCLKIndex = 0x44; - /* Special Timing: 848x480 parallel lvds */ - if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { - if(HwInfo->jChipType < SIS_315H) { + /* Special Timing: 848x480 and 856x480 parallel lvds panels */ + if(SiS_Pr->SiS_CustomT == CUT_PANEL848 || SiS_Pr->SiS_CustomT == CUT_PANEL856) { + if(SiS_Pr->ChipType < SIS_315H) { VCLKIndex = VCLK34_300; - /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */ + /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */ } else { VCLKIndex = VCLK34_315; /* if(resinfo == SIS_RI_1360x768) VCLKIndex = ?; */ } } +#endif - } else { + } else { - VCLKIndex = VCLKIndexGEN; - if(HwInfo->jChipType < SIS_315H) { - if(ModeNo > 0x13) { - if( (HwInfo->jChipType == SIS_630) && - (HwInfo->jChipRevision >= 0x30) ) { + VCLKIndex = VCLKIndexGENCRT; + if(SiS_Pr->ChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (SiS_Pr->ChipType == SIS_630) && + (SiS_Pr->ChipRevision >= 0x30) ) { if(VCLKIndex == 0x14) VCLKIndex = 0x2e; - } - } + } + } } - } + } } else { /* if not programming CRT2 */ - VCLKIndex = VCLKIndexGEN; - if(HwInfo->jChipType < SIS_315H) { - if(ModeNo > 0x13) { - if( (HwInfo->jChipType != SIS_630) && - (HwInfo->jChipType != SIS_300) ) { + VCLKIndex = VCLKIndexGENCRT; + if(SiS_Pr->ChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (SiS_Pr->ChipType != SIS_630) && + (SiS_Pr->ChipType != SIS_300) ) { if(VCLKIndex == 0x1b) VCLKIndex = 0x48; } #if 0 - if(HwInfo->jChipType == SIS_730) { + if(SiS_Pr->ChipType == SIS_730) { if(VCLKIndex == 0x0b) VCLKIndex = 0x40; /* 1024x768-70 */ if(VCLKIndex == 0x0d) VCLKIndex = 0x41; /* 1024x768-75 */ } @@ -2377,11 +2413,13 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "VCLKIndex %d (0x%x)\n", VCLKIndex, VCLKIndex); +#endif #endif - return(VCLKIndex); + return VCLKIndex; } /*********************************************/ @@ -2389,26 +2427,19 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ static void -SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo) +SiS_SetCRT2ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - USHORT i,j,modeflag; - USHORT tempcl,tempah=0; + unsigned short i, j, modeflag, tempah=0; + short tempcl; #if defined(SIS300) || defined(SIS315H) - USHORT tempbl; + unsigned short tempbl; #endif #ifdef SIS315H - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT tempah2, tempbl2; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short tempah2, tempbl2; #endif - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } + modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex); if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { @@ -2418,18 +2449,18 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } else { for(i=0,j=4; i<3; i++,j++) SiS_SetReg(SiS_Pr->SiS_Part1Port,j,0); - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0x7F); } tempcl = SiS_Pr->SiS_ModeType; - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 /* ---- 300 series ---- */ - /* For 301BDH: (with LCD via LVDS) */ - if(SiS_Pr->SiS_VBType & VB_NoLCD) { + /* For 301BDH: (with LCD via LVDS) */ + if(SiS_Pr->SiS_VBType & VB_NoLCD) { tempbl = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32); tempbl &= 0xef; tempbl |= 0x02; @@ -2438,16 +2469,16 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, tempbl &= 0xfd; } SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,tempbl); - } + } - if(ModeNo > 0x13) { - tempcl -= ModeVGA; - if((tempcl > 0) || (tempcl == 0)) { /* tempcl is USHORT -> always true! */ - tempah = ((0x10 >> tempcl) | 0x80); - } - } else tempah = 0x80; + if(ModeNo > 0x13) { + tempcl -= ModeVGA; + if(tempcl >= 0) { + tempah = ((0x10 >> tempcl) | 0x80); + } + } else tempah = 0x80; - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0xA0; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0xA0; #endif /* SIS300 */ @@ -2455,22 +2486,16 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, #ifdef SIS315H /* ------- 315/330 series ------ */ - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x08); - } - } - - if(ModeNo > 0x13) { - tempcl -= ModeVGA; - if((tempcl > 0) || (tempcl == 0)) { /* tempcl is USHORT -> always true! */ - tempah = (0x08 >> tempcl); - if (tempah == 0) tempah = 1; - tempah |= 0x40; - } - } else tempah = 0x40; + if(ModeNo > 0x13) { + tempcl -= ModeVGA; + if(tempcl >= 0) { + tempah = (0x08 >> tempcl); + if (tempah == 0) tempah = 1; + tempah |= 0x40; + } + } else tempah = 0x40; - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0x50; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempah ^= 0x50; #endif /* SIS315H */ @@ -2478,84 +2503,89 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; - if(HwInfo->jChipType < SIS_315H) { - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah); + if(SiS_Pr->ChipType < SIS_315H) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah); } else { - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah); - } else if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(IS_SIS740) { +#ifdef SIS315H + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah); + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(IS_SIS740) { SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,tempah); } else { - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah); } - } + } +#endif } if(SiS_Pr->SiS_VBType & VB_SISVB) { - tempah = 0x01; - if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - tempah |= 0x02; - } - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { - tempah ^= 0x05; - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { - tempah ^= 0x01; - } - } + tempah = 0x01; + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + tempah |= 0x02; + } + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempah ^= 0x05; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + tempah ^= 0x01; + } + } - if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; + if(SiS_Pr->ChipType < SIS_315H) { - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; - tempah = (tempah << 5) & 0xFF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,tempah); - tempah = (tempah >> 5) & 0xFF; + tempah = (tempah << 5) & 0xFF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,tempah); + tempah = (tempah >> 5) & 0xFF; - } else { + } else { - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2E,0xF8,tempah); + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0x08; + else if(!(SiS_IsDualEdge(SiS_Pr))) tempah |= 0x08; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2E,0xF0,tempah); + tempah &= ~0x08; - } + } - if((SiS_Pr->SiS_ModeType == ModeVGA) && (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) { - tempah |= 0x10; - } + if((SiS_Pr->SiS_ModeType == ModeVGA) && (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) { + tempah |= 0x10; + } tempah |= 0x80; - if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(SiS_Pr->SiS_VBType & VB_SIS301) { if(SiS_Pr->PanelXRes < 1280 && SiS_Pr->PanelYRes < 960) tempah &= ~0x80; - } + } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { if(!(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetYPbPr525p))) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - tempah |= 0x20; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + tempah |= 0x20; } - } - } + } + } - SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0D,0x40,tempah); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0D,0x40,tempah); tempah = 0x80; if(SiS_Pr->SiS_VBType & VB_SIS301) { if(SiS_Pr->PanelXRes < 1280 && SiS_Pr->PanelYRes < 960) tempah = 0; } - if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempah |= 0x40; + if(SiS_IsDualLink(SiS_Pr)) tempah |= 0x40; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) { - tempah |= 0x40; - } - } + tempah |= 0x40; + } + } - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0C,tempah); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0C,tempah); } else { /* LVDS */ - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { #ifdef SIS315H /* LVDS can only be slave in 8bpp modes */ @@ -2566,36 +2596,30 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } } - if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - tempah |= 0x02; - } + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) tempah |= 0x02; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - tempah ^= 0x01; - } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempah ^= 0x01; - if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) { - tempah = 1; - } + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 1; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2e,0xF0,tempah); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2e,0xF0,tempah); #endif - } else { + } else { #ifdef SIS300 tempah = 0; if( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) && (SiS_Pr->SiS_ModeType > ModeVGA) ) { - tempah |= 0x02; - } + tempah |= 0x02; + } tempah <<= 5; - if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; + if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,tempah); #endif - } + } } @@ -2603,10 +2627,10 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { #ifdef SIS315H - unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); + /* unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); */ /* The following is nearly unpreditable and varies from machine * to machine. Especially the 301DH seems to be a real trouble @@ -2619,25 +2643,28 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /* 740 variants match for 30xB, 301B-DH, 30xLV */ - if(!(IS_SIS740)) { - tempah = 0x04; /* For all bridges */ - tempbl = 0xfb; - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { - tempah = 0x00; - if(SiS_IsDualEdge(SiS_Pr, HwInfo)) { + if(!(IS_SIS740)) { + tempah = 0x04; /* For all bridges */ + tempbl = 0xfb; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempah = 0x00; + if(SiS_IsDualEdge(SiS_Pr)) { tempbl = 0xff; } - } - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah); + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah); } /* The following two are responsible for eventually wrong colors * in TV output. The DH (VB_NoLCD) conditions are unknown; the * b0 was found in some 651 machine (Pim; P4_23=0xe5); the b1 version * in a 650 box (Jake). What is the criteria? + * Addendum: Another combination 651+301B-DH(b1) (Rapo) needs same + * treatment like the 651+301B-DH(b0) case. Seems more to be the + * chipset than the bridge revision. */ - if((IS_SIS740) || (HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { + if((IS_SIS740) || (SiS_Pr->ChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { tempah = 0x30; tempbl = 0xc0; if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) || @@ -2649,20 +2676,30 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,tempbl); } else if(SiS_Pr->SiS_VBType & VB_SIS301) { /* Fixes "TV-blue-bug" on 315+301 */ - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2c,0xcf); /* For 301 */ + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2c,0xcf); /* For 301 */ SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f); - } else if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); /* For 30xLV */ - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x21,0xc0); - } else if((SiS_Pr->SiS_VBType & VB_NoLCD) && (bridgerev == 0xb0)) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); /* For 30xB-DH rev b0 (or "DH on 651"?) */ + } else if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); /* For 30xLV */ SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x21,0xc0); + } else if(SiS_Pr->SiS_VBType & VB_NoLCD) { /* For 301B-DH */ + tempah = 0x30; tempah2 = 0xc0; + tempbl = 0xcf; tempbl2 = 0x3f; + if(SiS_Pr->SiS_TVBlue == 0) { + tempah = tempah2 = 0x00; + } else if(SiS_Pr->SiS_TVBlue == -1) { + /* Set on 651/M650, clear on 315/650 */ + if(!(IS_SIS65x)) /* (bridgerev != 0xb0) */ { + tempah = tempah2 = 0x00; + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,tempbl,tempah); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,tempbl2,tempah2); } else { - tempah = 0x30; tempah2 = 0xc0; /* For 30xB (and 301BDH rev b1) */ + tempah = 0x30; tempah2 = 0xc0; /* For 30xB, 301C */ tempbl = 0xcf; tempbl2 = 0x3f; if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { tempah = tempah2 = 0x00; - if(SiS_IsDualEdge(SiS_Pr, HwInfo)) { + if(SiS_IsDualEdge(SiS_Pr)) { tempbl = tempbl2 = 0xff; } } @@ -2676,23 +2713,23 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,0x7f,tempah); } else { tempah = 0x00; - tempbl = 0x7f; - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { - tempbl = 0xff; - if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) tempah = 0x80; - } - SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah); + tempbl = 0x7f; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempbl = 0xff; + if(!(SiS_IsDualEdge(SiS_Pr))) tempah = 0x80; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah); } #endif /* SIS315H */ - } else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + } else if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { #ifdef SIS300 - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f); - if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) || - ((SiS_Pr->SiS_VBType & VB_NoLCD) && + if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) || + ((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD))) { SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x23,0x7F); } else { @@ -2702,9 +2739,9 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x0D,0x80); - if(SiS_Pr->SiS_VBType & VB_SIS301C) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x0D,0x80); + if(SiS_Pr->SiS_VBType & VB_SIS30xCLV) { SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3A,0xC0); } } @@ -2712,16 +2749,16 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } else { /* LVDS */ #ifdef SIS315H - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - tempah = 0x04; + tempah = 0x04; tempbl = 0xfb; - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { - tempah = 0x00; - if(SiS_IsDualEdge(SiS_Pr, HwInfo)) tempbl = 0xff; - } + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + tempah = 0x00; + if(SiS_IsDualEdge(SiS_Pr)) tempbl = 0xff; + } SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah); if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) { @@ -2730,7 +2767,7 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); - } else if(HwInfo->jChipType == SIS_550) { + } else if(SiS_Pr->ChipType == SIS_550) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2c,0x30); @@ -2748,212 +2785,120 @@ SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /* GET RESOLUTION DATA */ /*********************************************/ -USHORT -SiS_GetResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex) +unsigned short +SiS_GetResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - if(ModeNo <= 0x13) return((USHORT)SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo); - else return((USHORT)SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO); + if(ModeNo <= 0x13) + return ((unsigned short)SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo); + else + return ((unsigned short)SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO); } static void -SiS_GetCRT2ResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo) +SiS_GetCRT2ResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - USHORT xres,yres,modeflag=0,resindex; + unsigned short xres, yres, modeflag=0, resindex; - if(SiS_Pr->UseCustomMode) { - xres = SiS_Pr->CHDisplay; - if(SiS_Pr->CModeFlag & HalfDCLK) xres *= 2; - SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres; - yres = SiS_Pr->CVDisplay; - if(SiS_Pr->CModeFlag & DoubleScanMode) yres *= 2; - SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres; - return; - } - - resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex); + if(SiS_Pr->UseCustomMode) { + xres = SiS_Pr->CHDisplay; + if(SiS_Pr->CModeFlag & HalfDCLK) xres <<= 1; + SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres; + /* DoubleScanMode-check done in CheckCalcCustomMode()! */ + SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = SiS_Pr->CVDisplay; + return; + } - if(ModeNo <= 0x13) { - xres = SiS_Pr->SiS_StResInfo[resindex].HTotal; - yres = SiS_Pr->SiS_StResInfo[resindex].VTotal; - } else { - xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal; - yres = SiS_Pr->SiS_ModeResInfo[resindex].VTotal; - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } + resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex); - if(!SiS_Pr->SiS_IF_DEF_DSTN && !SiS_Pr->SiS_IF_DEF_FSTN) { + if(ModeNo <= 0x13) { + xres = SiS_Pr->SiS_StResInfo[resindex].HTotal; + yres = SiS_Pr->SiS_StResInfo[resindex].VTotal; + } else { + xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal; + yres = SiS_Pr->SiS_ModeResInfo[resindex].VTotal; + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } - if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1)) { - if((ModeNo != 0x03) && (SiS_Pr->SiS_SetFlag & SetDOSMode)) { - if(yres == 350) yres = 400; - } - if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x3a) & 0x01) { - if(ModeNo == 0x12) yres = 400; - } - } + if(!SiS_Pr->SiS_IF_DEF_DSTN && !SiS_Pr->SiS_IF_DEF_FSTN) { - if(modeflag & HalfDCLK) xres *= 2; - if(modeflag & DoubleScanMode) yres *= 2; + if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1)) { + if((ModeNo != 0x03) && (SiS_Pr->SiS_SetFlag & SetDOSMode)) { + if(yres == 350) yres = 400; + } + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x3a) & 0x01) { + if(ModeNo == 0x12) yres = 400; + } + } - } + if(modeflag & HalfDCLK) xres <<= 1; + if(modeflag & DoubleScanMode) yres <<= 1; - if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + } -#if 0 - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCDA | SetCRT2ToLCD | SetCRT2ToHiVision)) { - if(xres == 720) xres = 640; - } -#endif + if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - switch(SiS_Pr->SiS_LCDResInfo) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + switch(SiS_Pr->SiS_LCDResInfo) { case Panel_1024x768: if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { - if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { - if(yres == 350) yres = 357; - if(yres == 400) yres = 420; - if(yres == 480) yres = 525; - } - } + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + if(yres == 350) yres = 357; + if(yres == 400) yres = 420; + if(yres == 480) yres = 525; + } + } break; case Panel_1280x1024: if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { /* BIOS bug - does this regardless of scaling */ - if(yres == 400) yres = 405; + if(yres == 400) yres = 405; + } + if(yres == 350) yres = 360; + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + if(yres == 360) yres = 375; } - if(yres == 350) yres = 360; - if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { - if(yres == 360) yres = 375; - } break; case Panel_1600x1200: if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { - if(yres == 1024) yres = 1056; - } + if(yres == 1024) yres = 1056; + } break; - } - } + } + } - } else { + } else { - if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) { - if(xres == 720) xres = 640; - } - } else if(xres == 720) xres = 640; + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) { + if(xres == 720) xres = 640; + } + } else if(xres == 720) xres = 640; - if(SiS_Pr->SiS_SetFlag & SetDOSMode) { - yres = 400; - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480; - } else { - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480; - } - if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) yres = 480; - } + if(SiS_Pr->SiS_SetFlag & SetDOSMode) { + yres = 400; + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480; + } else { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480; + } + if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) yres = 480; + } - } - SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres; - SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres; + } + SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres; + SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres; } /*********************************************/ /* GET CRT2 TIMING DATA */ /*********************************************/ -static BOOLEAN -SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, USHORT *ResIndex, - USHORT *DisplayType) - { - USHORT modeflag=0; - - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { - if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return FALSE; - } - } else if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return FALSE; - } else - return FALSE; - - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - } - - (*ResIndex) &= 0x3F; - - if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { - (*DisplayType) = 18; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - (*DisplayType) += 2; - if(SiS_Pr->SiS_ModeType > ModeVGA) { - if(SiS_Pr->SiS_CHSOverScan) (*DisplayType) = 99; - } - if(SiS_Pr->SiS_TVMode & TVSetPALM) { - (*DisplayType) = 18; /* PALM uses NTSC data */ - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; - } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { - (*DisplayType) = 20; /* PALN uses PAL data */ - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; - } - } - } else { - switch(SiS_Pr->SiS_LCDResInfo) { - case Panel_640x480: (*DisplayType) = 50; break; - case Panel_640x480_2: (*DisplayType) = 52; break; - case Panel_640x480_3: (*DisplayType) = 54; break; - case Panel_800x600: (*DisplayType) = 0; break; - case Panel_1024x600: (*DisplayType) = 23; break; - case Panel_1024x768: (*DisplayType) = 4; break; - case Panel_1152x768: (*DisplayType) = 27; break; - case Panel_1280x768: (*DisplayType) = 40; break; - case Panel_1280x1024: (*DisplayType) = 8; break; - case Panel_1400x1050: (*DisplayType) = 14; break; - case Panel_1600x1200: (*DisplayType) = 36; break; - default: return FALSE; - } - - if(modeflag & HalfDCLK) (*DisplayType)++; - - switch(SiS_Pr->SiS_LCDResInfo) { - case Panel_640x480: - case Panel_640x480_2: - case Panel_640x480_3: - break; - default: - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) (*DisplayType) += 2; - } - - if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - (*DisplayType) = 12; - if(modeflag & HalfDCLK) (*DisplayType)++; - } - } - -#if 0 - if(SiS_Pr->SiS_IF_DEF_FSTN) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480){ - (*DisplayType) = 22; - } - } -#endif - - return TRUE; -} - static void -SiS_GetCRT2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, - USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex, - PSIS_HW_INFO HwInfo) +SiS_GetCRT2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex, unsigned short *CRT2Index, + unsigned short *ResIndex) { - USHORT tempbx=0,tempal=0,resinfo=0; + unsigned short tempbx=0, tempal=0, resinfo=0; if(ModeNo <= 0x13) { tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; @@ -2966,18 +2911,20 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { /* LCD */ - tempbx = SiS_Pr->SiS_LCDResInfo; + tempbx = SiS_Pr->SiS_LCDResInfo; if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 32; + /* patch index */ if(SiS_Pr->SiS_LCDResInfo == Panel_1680x1050) { if (resinfo == SIS_RI_1280x800) tempal = 9; else if(resinfo == SIS_RI_1400x1050) tempal = 11; } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x800) || - (SiS_Pr->SiS_LCDResInfo == Panel_1280x800_2)) { + (SiS_Pr->SiS_LCDResInfo == Panel_1280x800_2) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x854)) { if (resinfo == SIS_RI_1280x768) tempal = 9; } - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { /* Pass 1:1 only (center-screen handled outside) */ /* This is never called for the panel's native resolution */ /* since Pass1:1 will not be set in this case */ @@ -2991,8 +2938,8 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { - tempbx = 200; - if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx++; + tempbx = 200; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx++; } } } @@ -3000,23 +2947,23 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, } else { /* TV */ - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - /* if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_TVMode &= (~TVSetTVSimuMode); */ - tempbx = 2; - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + /* if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_TVMode &= (~TVSetTVSimuMode); */ + tempbx = 2; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { tempbx = 13; - if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) tempbx = 14; - } + if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) tempbx = 14; + } } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempbx = 7; - else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tempbx = 6; - else tempbx = 5; - if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) tempbx += 5; - } else { - if(SiS_Pr->SiS_TVMode & TVSetPAL) tempbx = 3; - else tempbx = 4; - if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) tempbx += 5; - } + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempbx = 7; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tempbx = 6; + else tempbx = 5; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) tempbx += 5; + } else { + if(SiS_Pr->SiS_TVMode & TVSetPAL) tempbx = 3; + else tempbx = 4; + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) tempbx += 5; + } } @@ -3024,26 +2971,34 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, if(ModeNo > 0x13) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) { - if(tempal == 6) tempal = 7; - if((resinfo == SIS_RI_720x480) || - (resinfo == SIS_RI_720x576) || - (resinfo == SIS_RI_768x576)) { + switch(resinfo) { + case SIS_RI_720x480: tempal = 6; - if(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetPALN)) { - if(resinfo == SIS_RI_720x480) tempal = 9; + if(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetPALN)) tempal = 9; + break; + case SIS_RI_720x576: + case SIS_RI_768x576: + case SIS_RI_1024x576: /* Not in NTSC or YPBPR mode (except 1080i)! */ + tempal = 6; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempal = 8; } - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { - if(resinfo == SIS_RI_1024x768) tempal = 8; + break; + case SIS_RI_800x480: + tempal = 4; + break; + case SIS_RI_512x384: + case SIS_RI_1024x768: + tempal = 7; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tempal = 8; } - if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { - if((resinfo == SIS_RI_720x576) || - (resinfo == SIS_RI_768x576)) { - tempal = 8; - } - if(resinfo == SIS_RI_1280x720) tempal = 9; + break; + case SIS_RI_1280x720: + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempal = 9; } + break; } } } @@ -3056,65 +3011,60 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, tempbx = 0; if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { - tempbx = 10; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - tempbx += 2; + tempbx = 90; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tempbx = 92; if(SiS_Pr->SiS_ModeType > ModeVGA) { if(SiS_Pr->SiS_CHSOverScan) tempbx = 99; } - if(SiS_Pr->SiS_TVMode & TVSetPALM) { - tempbx = 90; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; - } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { - tempbx = 92; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; - } - } + if(SiS_Pr->SiS_TVMode & TVSetPALM) tempbx = 94; + else if(SiS_Pr->SiS_TVMode & TVSetPALN) tempbx = 96; + } + if(tempbx != 99) { + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx++; + } } else { - switch(SiS_Pr->SiS_LCDResInfo) { - case Panel_640x480: tempbx = 6; break; - case Panel_640x480_2: - case Panel_640x480_3: tempbx = 30; break; - case Panel_800x600: tempbx = 0; break; - case Panel_1024x600: tempbx = 15; break; - case Panel_1024x768: tempbx = 2; break; - case Panel_1152x768: tempbx = 17; break; - case Panel_1280x768: tempbx = 18; break; - case Panel_1280x1024: tempbx = 4; break; - case Panel_1400x1050: tempbx = 8; break; - case Panel_1600x1200: tempbx = 21; break; + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: tempbx = 12; break; + case Panel_320x240_1: tempbx = 10; break; + case Panel_320x240_2: + case Panel_320x240_3: tempbx = 14; break; + case Panel_800x600: tempbx = 16; break; + case Panel_1024x600: tempbx = 18; break; + case Panel_1152x768: + case Panel_1024x768: tempbx = 20; break; + case Panel_1280x768: tempbx = 22; break; + case Panel_1280x1024: tempbx = 24; break; + case Panel_1400x1050: tempbx = 26; break; + case Panel_1600x1200: tempbx = 28; break; +#ifdef SIS300 case Panel_Barco1366: tempbx = 80; break; +#endif } switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_320x240_1: + case Panel_320x240_2: + case Panel_320x240_3: case Panel_640x480: - case Panel_640x480_2: - case Panel_640x480_3: break; default: if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; } - if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempbx = 7; + if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempbx = 30; +#ifdef SIS300 if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { tempbx = 82; if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; - } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { + } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848 || SiS_Pr->SiS_CustomT == CUT_PANEL856) { tempbx = 84; if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; } - - if((SiS_Pr->SiS_CustomT != CUT_BARCO1366) && - (SiS_Pr->SiS_CustomT != CUT_PANEL848)) { - if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && - (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { - tempal = 0; - } - } +#endif } @@ -3124,12 +3074,11 @@ SiS_GetCRT2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, } static void -SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, - USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo) +SiS_GetRAMDAC2DATA(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { - USHORT tempax=0,tempbx=0; - USHORT temp1=0,modeflag=0,tempcx=0; - USHORT index; + unsigned short tempax=0, tempbx=0, index, dotclock; + unsigned short temp1=0, modeflag=0, tempcx=0; SiS_Pr->SiS_RVBHCMAX = 1; SiS_Pr->SiS_RVBHCFACT = 1; @@ -3143,10 +3092,12 @@ SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, tempbx = SiS_Pr->SiS_StandTable[index].CRTC[6]; temp1 = SiS_Pr->SiS_StandTable[index].CRTC[7]; + dotclock = (modeflag & Charx8Dot) ? 8 : 9; + } else { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + index = SiS_GetRefCRT1CRTC(SiS_Pr, RefreshRateTableIndex, SiS_Pr->SiS_UseWideCRT2); tempax = SiS_Pr->SiS_CRT1Table[index].CR[0]; tempax |= (SiS_Pr->SiS_CRT1Table[index].CR[14] << 8); @@ -3158,22 +3109,16 @@ SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, tempbx |= tempcx; temp1 = SiS_Pr->SiS_CRT1Table[index].CR[7]; + dotclock = 8; + } if(temp1 & 0x01) tempbx |= 0x0100; if(temp1 & 0x20) tempbx |= 0x0200; tempax += 5; - - /* Charx8Dot is no more used (and assumed), so we set it */ - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - modeflag |= Charx8Dot; - } - - if(modeflag & Charx8Dot) tempax *= 8; - else tempax *= 9; - - if(modeflag & HalfDCLK) tempax <<= 1; + tempax *= dotclock; + if(modeflag & HalfDCLK) tempax <<= 1; tempbx++; @@ -3182,13 +3127,56 @@ SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, } static void -SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +SiS_CalcPanelLinkTiming(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex) +{ + unsigned short ResIndex; + + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + if(SiS_Pr->UseCustomMode) { + ResIndex = SiS_Pr->CHTotal; + if(SiS_Pr->CModeFlag & HalfDCLK) ResIndex <<= 1; + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = ResIndex; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal; + } else { + if(ModeNo < 0x13) { + ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS; + } + if(ResIndex == 0x09) { + if(SiS_Pr->Alternate1600x1200) ResIndex = 0x20; /* 1600x1200 LCDA */ + else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) ResIndex = 0x21; /* 1600x1200 LVDS */ + } + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAVT; + SiS_Pr->SiS_HT = SiS_Pr->SiS_NoScaleData[ResIndex].LCDHT; + SiS_Pr->SiS_VT = SiS_Pr->SiS_NoScaleData[ResIndex].LCDVT; + } + } else { + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + } + } else { + /* This handles custom modes and custom panels */ + SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; + SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT - (SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE); + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT - (SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE); + } +} + +static void +SiS_GetCRT2DataLVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { - USHORT CRT2Index, ResIndex; - const SiS_LVDSDataStruct *LVDSData = NULL; + unsigned short CRT2Index, ResIndex, backup; + const struct SiS_LVDSData *LVDSData = NULL; - SiS_GetCRT2ResInfo(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_GetCRT2ResInfo(SiS_Pr, ModeNo, ModeIdIndex); if(SiS_Pr->SiS_VBType & VB_SISVB) { SiS_Pr->SiS_RVBHCMAX = 1; @@ -3199,133 +3187,94 @@ SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, SiS_Pr->SiS_RY2COE = 0; SiS_Pr->SiS_RY3COE = 0; SiS_Pr->SiS_RY4COE = 0; + SiS_Pr->SiS_RVBHRS2 = 0; } if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { #ifdef SIS315H - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - if(SiS_Pr->UseCustomMode) { - SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->CHTotal; - SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal; - } else { - if(ModeNo < 0x13) { - ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; - } else { - ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS; - } - SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAHT; - SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAVT; - SiS_Pr->SiS_HT = SiS_Pr->SiS_NoScaleData[ResIndex].LCDHT; - SiS_Pr->SiS_VT = SiS_Pr->SiS_NoScaleData[ResIndex].LCDVT; - } - } else { - SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->PanelHT; - SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->PanelVT; - } - } else { - /* This handles custom modes and custom panels */ - SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; - SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; - SiS_Pr->SiS_HT = SiS_Pr->PanelHT; - SiS_Pr->SiS_VT = SiS_Pr->PanelVT; - SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT - (SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE); - SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT - (SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE); - } - - SiS_CalcLCDACRT1Timing(SiS_Pr,ModeNo,ModeIdIndex); - + SiS_CalcPanelLinkTiming(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + SiS_CalcLCDACRT1Timing(SiS_Pr, ModeNo, ModeIdIndex); #endif } else { /* 301BDH needs LVDS Data */ + backup = SiS_Pr->SiS_IF_DEF_LVDS; if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { SiS_Pr->SiS_IF_DEF_LVDS = 1; } SiS_GetCRT2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, - &CRT2Index, &ResIndex, HwInfo); + &CRT2Index, &ResIndex); - /* 301BDH needs LVDS Data */ - if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { - SiS_Pr->SiS_IF_DEF_LVDS = 0; - } + SiS_Pr->SiS_IF_DEF_LVDS = backup; - switch (CRT2Index) { - case 0: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1; break; - case 1: LVDSData = SiS_Pr->SiS_LVDS800x600Data_2; break; - case 2: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; - case 3: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2; break; - case 4: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1; break; - case 5: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2; break; - case 6: LVDSData = SiS_Pr->SiS_LVDS640x480Data_1; break; - case 7: LVDSData = SiS_Pr->SiS_LVDSXXXxXXXData_1; break; - case 8: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_1; break; - case 9: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_2; break; - case 10: LVDSData = SiS_Pr->SiS_CHTVUNTSCData; break; - case 11: LVDSData = SiS_Pr->SiS_CHTVONTSCData; break; - case 12: LVDSData = SiS_Pr->SiS_CHTVUPALData; break; - case 13: LVDSData = SiS_Pr->SiS_CHTVOPALData; break; - case 14: LVDSData = SiS_Pr->SiS_LVDS320x480Data_1; break; - case 15: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1; break; - case 16: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_2; break; - case 17: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_1; break; - case 18: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_2; break; - case 19: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_1; break; - case 20: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_2; break; - case 21: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_1; break; - case 22: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_2; break; - case 30: LVDSData = SiS_Pr->SiS_LVDS640x480Data_2; break; + switch(CRT2Index) { + case 10: LVDSData = SiS_Pr->SiS_LVDS320x240Data_1; break; + case 14: LVDSData = SiS_Pr->SiS_LVDS320x240Data_2; break; + case 12: LVDSData = SiS_Pr->SiS_LVDS640x480Data_1; break; + case 16: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1; break; + case 18: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1; break; + case 20: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; +#ifdef SIS300 case 80: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1; break; case 81: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2; break; case 82: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1; break; - case 83: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_2; break; case 84: LVDSData = SiS_Pr->SiS_LVDS848x480Data_1; break; case 85: LVDSData = SiS_Pr->SiS_LVDS848x480Data_2; break; - case 90: LVDSData = SiS_Pr->SiS_CHTVUPALMData; break; - case 91: LVDSData = SiS_Pr->SiS_CHTVOPALMData; break; - case 92: LVDSData = SiS_Pr->SiS_CHTVUPALNData; break; - case 93: LVDSData = SiS_Pr->SiS_CHTVOPALNData; break; - case 99: LVDSData = SiS_Pr->SiS_CHTVSOPALData; break; /* Super Overscan */ - default: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; +#endif + case 90: LVDSData = SiS_Pr->SiS_CHTVUNTSCData; break; + case 91: LVDSData = SiS_Pr->SiS_CHTVONTSCData; break; + case 92: LVDSData = SiS_Pr->SiS_CHTVUPALData; break; + case 93: LVDSData = SiS_Pr->SiS_CHTVOPALData; break; + case 94: LVDSData = SiS_Pr->SiS_CHTVUPALMData; break; + case 95: LVDSData = SiS_Pr->SiS_CHTVOPALMData; break; + case 96: LVDSData = SiS_Pr->SiS_CHTVUPALNData; break; + case 97: LVDSData = SiS_Pr->SiS_CHTVOPALNData; break; + case 99: LVDSData = SiS_Pr->SiS_CHTVSOPALData; break; } - SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT; - SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT; - SiS_Pr->SiS_HT = (LVDSData+ResIndex)->LCDHT; - SiS_Pr->SiS_VT = (LVDSData+ResIndex)->LCDVT; - - if(!(SiS_Pr->SiS_VBType & VB_SISVB)) { - if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { - if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (SiS_Pr->SiS_SetFlag & SetDOSMode)) { - SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; - SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; - if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { - if(ResIndex < 0x08) { - SiS_Pr->SiS_HDE = 1280; - SiS_Pr->SiS_VDE = 1024; - } - } - } + if(LVDSData) { + SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT; + SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT; + SiS_Pr->SiS_HT = (LVDSData+ResIndex)->LCDHT; + SiS_Pr->SiS_VT = (LVDSData+ResIndex)->LCDVT; + } else { + SiS_CalcPanelLinkTiming(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + + if( (!(SiS_Pr->SiS_VBType & VB_SISVB)) && + (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && + (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) ) { + if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || + (SiS_Pr->SiS_SetFlag & SetDOSMode) ) { + SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; + SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; +#ifdef SIS300 + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + if(ResIndex < 0x08) { + SiS_Pr->SiS_HDE = 1280; + SiS_Pr->SiS_VDE = 1024; + } + } +#endif } } } } static void -SiS_GetCRT2Data301(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, - PSIS_HW_INFO HwInfo) -{ - UCHAR *ROMAddr = NULL; - USHORT tempax,tempbx,modeflag,romptr=0; - USHORT resinfo,CRT2Index,ResIndex; - const SiS_LCDDataStruct *LCDPtr = NULL; - const SiS_TVDataStruct *TVPtr = NULL; +SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned char *ROMAddr = NULL; + unsigned short tempax, tempbx, modeflag, romptr=0; + unsigned short resinfo, CRT2Index, ResIndex; + const struct SiS_LCDData *LCDPtr = NULL; + const struct SiS_TVData *TVPtr = NULL; #ifdef SIS315H - SHORT resinfo661; + short resinfo661; #endif if(ModeNo <= 0x13) { @@ -3340,67 +3289,69 @@ SiS_GetCRT2Data301(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, #ifdef SIS315H resinfo661 = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].ROMMODEIDX661; if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && - (SiS_Pr->SiS_SetFlag & LCDVESATiming) && - (resinfo661 >= 0) && + (SiS_Pr->SiS_SetFlag & LCDVESATiming) && + (resinfo661 >= 0) && (SiS_Pr->SiS_NeedRomModeData) ) { - if((ROMAddr = GetLCDStructPtr661(SiS_Pr, HwInfo))) { + if((ROMAddr = GetLCDStructPtr661(SiS_Pr))) { if((romptr = (SISGETROMW(21)))) { - romptr += (resinfo661 * 10); - ROMAddr = HwInfo->pjVirtualRomBase; + romptr += (resinfo661 * 10); + ROMAddr = SiS_Pr->VirtualRomBase; } } } #endif } - + SiS_Pr->SiS_NewFlickerMode = 0; SiS_Pr->SiS_RVBHRS = 50; SiS_Pr->SiS_RY1COE = 0; SiS_Pr->SiS_RY2COE = 0; SiS_Pr->SiS_RY3COE = 0; SiS_Pr->SiS_RY4COE = 0; + SiS_Pr->SiS_RVBHRS2 = 0; - SiS_GetCRT2ResInfo(SiS_Pr,ModeNo,ModeIdIndex,HwInfo); + SiS_GetCRT2ResInfo(SiS_Pr,ModeNo,ModeIdIndex); - if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { if(SiS_Pr->UseCustomMode) { - SiS_Pr->SiS_RVBHCMAX = 1; - SiS_Pr->SiS_RVBHCFACT = 1; - SiS_Pr->SiS_VGAHT = SiS_Pr->CHTotal; - SiS_Pr->SiS_VGAVT = SiS_Pr->CVTotal; - SiS_Pr->SiS_HT = SiS_Pr->CHTotal; - SiS_Pr->SiS_VT = SiS_Pr->CVTotal; + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; SiS_Pr->SiS_HDE = SiS_Pr->SiS_VGAHDE; - SiS_Pr->SiS_VDE = SiS_Pr->SiS_VGAVDE; + SiS_Pr->SiS_VDE = SiS_Pr->SiS_VGAVDE; + + tempax = SiS_Pr->CHTotal; + if(modeflag & HalfDCLK) tempax <<= 1; + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal; } else { - SiS_GetRAMDAC2DATA(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + SiS_GetRAMDAC2DATA(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex, - &CRT2Index,&ResIndex,HwInfo); + &CRT2Index,&ResIndex); switch(CRT2Index) { - case 2: TVPtr = SiS_Pr->SiS_ExtHiTVData; break; - case 3: TVPtr = SiS_Pr->SiS_ExtPALData; break; - case 4: TVPtr = SiS_Pr->SiS_ExtNTSCData; break; - case 5: TVPtr = SiS_Pr->SiS_Ext525iData; break; - case 6: TVPtr = SiS_Pr->SiS_Ext525pData; break; - case 7: TVPtr = SiS_Pr->SiS_Ext750pData; break; - case 8: TVPtr = SiS_Pr->SiS_StPALData; break; - case 9: TVPtr = SiS_Pr->SiS_StNTSCData; break; - case 10: TVPtr = SiS_Pr->SiS_St525iData; break; - case 11: TVPtr = SiS_Pr->SiS_St525pData; break; - case 12: TVPtr = SiS_Pr->SiS_St750pData; break; - case 13: TVPtr = SiS_Pr->SiS_St1HiTVData; break; - case 14: TVPtr = SiS_Pr->SiS_St2HiTVData; break; - default: TVPtr = SiS_Pr->SiS_StPALData; break; + case 2: TVPtr = SiS_Pr->SiS_ExtHiTVData; break; + case 3: TVPtr = SiS_Pr->SiS_ExtPALData; break; + case 4: TVPtr = SiS_Pr->SiS_ExtNTSCData; break; + case 5: TVPtr = SiS_Pr->SiS_Ext525iData; break; + case 6: TVPtr = SiS_Pr->SiS_Ext525pData; break; + case 7: TVPtr = SiS_Pr->SiS_Ext750pData; break; + case 8: TVPtr = SiS_Pr->SiS_StPALData; break; + case 9: TVPtr = SiS_Pr->SiS_StNTSCData; break; + case 10: TVPtr = SiS_Pr->SiS_St525iData; break; + case 11: TVPtr = SiS_Pr->SiS_St525pData; break; + case 12: TVPtr = SiS_Pr->SiS_St750pData; break; + case 13: TVPtr = SiS_Pr->SiS_St1HiTVData; break; + case 14: TVPtr = SiS_Pr->SiS_St2HiTVData; break; + default: TVPtr = SiS_Pr->SiS_StPALData; break; } SiS_Pr->SiS_RVBHCMAX = (TVPtr+ResIndex)->RVBHCMAX; @@ -3409,73 +3360,77 @@ SiS_GetCRT2Data301(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, SiS_Pr->SiS_VGAVT = (TVPtr+ResIndex)->VGAVT; SiS_Pr->SiS_HDE = (TVPtr+ResIndex)->TVHDE; SiS_Pr->SiS_VDE = (TVPtr+ResIndex)->TVVDE; - SiS_Pr->SiS_RVBHRS = (TVPtr+ResIndex)->RVBHRS; - SiS_Pr->SiS_NewFlickerMode = (TVPtr+ResIndex)->FlickerMode; + SiS_Pr->SiS_RVBHRS2 = (TVPtr+ResIndex)->RVBHRS2 & 0x0fff; if(modeflag & HalfDCLK) { - SiS_Pr->SiS_RVBHRS = (TVPtr+ResIndex)->HALFRVBHRS; + SiS_Pr->SiS_RVBHRS = (TVPtr+ResIndex)->HALFRVBHRS; + if(SiS_Pr->SiS_RVBHRS2) { + SiS_Pr->SiS_RVBHRS2 = ((SiS_Pr->SiS_RVBHRS2 + 3) >> 1) - 3; + tempax = ((TVPtr+ResIndex)->RVBHRS2 >> 12) & 0x07; + if((TVPtr+ResIndex)->RVBHRS2 & 0x8000) SiS_Pr->SiS_RVBHRS2 -= tempax; + else SiS_Pr->SiS_RVBHRS2 += tempax; + } + } else { + SiS_Pr->SiS_RVBHRS = (TVPtr+ResIndex)->RVBHRS; } + SiS_Pr->SiS_NewFlickerMode = ((TVPtr+ResIndex)->FlickerMode) << 7; if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if((resinfo == SIS_RI_1024x768) || - (resinfo == SIS_RI_1280x1024) || - (resinfo == SIS_RI_1280x720)) { + if((resinfo == SIS_RI_960x600) || + (resinfo == SIS_RI_1024x768) || + (resinfo == SIS_RI_1280x1024) || + (resinfo == SIS_RI_1280x720)) { SiS_Pr->SiS_NewFlickerMode = 0x40; } - if(SiS_Pr->SiS_VGAVDE == 350) SiS_Pr->SiS_TVMode |= TVSetTVSimuMode; + if(SiS_Pr->SiS_VGAVDE == 350) SiS_Pr->SiS_TVMode |= TVSetTVSimuMode; - SiS_Pr->SiS_HT = ExtHiTVHT; - SiS_Pr->SiS_VT = ExtHiTVVT; - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { - SiS_Pr->SiS_HT = StHiTVHT; - SiS_Pr->SiS_VT = StHiTVVT; -#if 0 - if(!(modeflag & Charx8Dot)) { - SiS_Pr->SiS_HT = StHiTextTVHT; - SiS_Pr->SiS_VT = StHiTextTVVT; - } -#endif - } - } + SiS_Pr->SiS_HT = ExtHiTVHT; + SiS_Pr->SiS_VT = ExtHiTVVT; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { + SiS_Pr->SiS_HT = StHiTVHT; + SiS_Pr->SiS_VT = StHiTVVT; + } + } } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { - SiS_Pr->SiS_HT = 1650; - SiS_Pr->SiS_VT = 750; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + SiS_Pr->SiS_HT = 1650; + SiS_Pr->SiS_VT = 750; } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { SiS_Pr->SiS_HT = NTSCHT; + if(SiS_Pr->SiS_TVMode & TVSet525p1024) SiS_Pr->SiS_HT = NTSC2HT; SiS_Pr->SiS_VT = NTSCVT; - } else { - SiS_Pr->SiS_HT = NTSCHT; + } else { + SiS_Pr->SiS_HT = NTSCHT; if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) SiS_Pr->SiS_HT = NTSC2HT; - SiS_Pr->SiS_VT = NTSCVT; - } + SiS_Pr->SiS_VT = NTSCVT; + } } else { - SiS_Pr->SiS_RY1COE = (TVPtr+ResIndex)->RY1COE; - SiS_Pr->SiS_RY2COE = (TVPtr+ResIndex)->RY2COE; - SiS_Pr->SiS_RY3COE = (TVPtr+ResIndex)->RY3COE; - SiS_Pr->SiS_RY4COE = (TVPtr+ResIndex)->RY4COE; + SiS_Pr->SiS_RY1COE = (TVPtr+ResIndex)->RY1COE; + SiS_Pr->SiS_RY2COE = (TVPtr+ResIndex)->RY2COE; + SiS_Pr->SiS_RY3COE = (TVPtr+ResIndex)->RY3COE; + SiS_Pr->SiS_RY4COE = (TVPtr+ResIndex)->RY4COE; - if(modeflag & HalfDCLK) { - SiS_Pr->SiS_RY1COE = 0x00; - SiS_Pr->SiS_RY2COE = 0xf4; - SiS_Pr->SiS_RY3COE = 0x10; - SiS_Pr->SiS_RY4COE = 0x38; - } + if(modeflag & HalfDCLK) { + SiS_Pr->SiS_RY1COE = 0x00; + SiS_Pr->SiS_RY2COE = 0xf4; + SiS_Pr->SiS_RY3COE = 0x10; + SiS_Pr->SiS_RY4COE = 0x38; + } - if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { - SiS_Pr->SiS_HT = NTSCHT; + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + SiS_Pr->SiS_HT = NTSCHT; if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) SiS_Pr->SiS_HT = NTSC2HT; - SiS_Pr->SiS_VT = NTSCVT; - } else { - SiS_Pr->SiS_HT = PALHT; - SiS_Pr->SiS_VT = PALVT; - } + SiS_Pr->SiS_VT = NTSCVT; + } else { + SiS_Pr->SiS_HT = PALHT; + SiS_Pr->SiS_VT = PALVT; + } } @@ -3486,42 +3441,53 @@ SiS_GetCRT2Data301(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, if(SiS_Pr->UseCustomMode) { - SiS_Pr->SiS_VGAHT = SiS_Pr->CHTotal; - SiS_Pr->SiS_VGAVT = SiS_Pr->CVTotal; - SiS_Pr->SiS_HT = SiS_Pr->CHTotal; - SiS_Pr->SiS_VT = SiS_Pr->CVTotal; SiS_Pr->SiS_HDE = SiS_Pr->SiS_VGAHDE; - SiS_Pr->SiS_VDE = SiS_Pr->SiS_VGAVDE; + SiS_Pr->SiS_VDE = SiS_Pr->SiS_VGAVDE; + + tempax = SiS_Pr->CHTotal; + if(modeflag & HalfDCLK) tempax <<= 1; + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal; } else { - BOOLEAN gotit = FALSE; + BOOLEAN gotit = FALSE; - if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { - SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT; - SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT; - SiS_Pr->SiS_HT = SiS_Pr->PanelHT; - SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; gotit = TRUE; } else if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) && (romptr) && (ROMAddr) ) { #ifdef SIS315H SiS_Pr->SiS_RVBHCMAX = ROMAddr[romptr]; - SiS_Pr->SiS_RVBHCFACT = ROMAddr[romptr+1]; - SiS_Pr->SiS_VGAHT = ROMAddr[romptr+2] | ((ROMAddr[romptr+3] & 0x0f) << 8); - SiS_Pr->SiS_VGAVT = ROMAddr[romptr+4] | ((ROMAddr[romptr+3] & 0xf0) << 4); - SiS_Pr->SiS_HT = ROMAddr[romptr+5] | ((ROMAddr[romptr+6] & 0x0f) << 8); - SiS_Pr->SiS_VT = ROMAddr[romptr+7] | ((ROMAddr[romptr+6] & 0xf0) << 4); + SiS_Pr->SiS_RVBHCFACT = ROMAddr[romptr+1]; + SiS_Pr->SiS_VGAHT = ROMAddr[romptr+2] | ((ROMAddr[romptr+3] & 0x0f) << 8); + SiS_Pr->SiS_VGAVT = (ROMAddr[romptr+4] << 4) | ((ROMAddr[romptr+3] & 0xf0) >> 4); + SiS_Pr->SiS_HT = ROMAddr[romptr+5] | ((ROMAddr[romptr+6] & 0x0f) << 8); + SiS_Pr->SiS_VT = (ROMAddr[romptr+7] << 4) | ((ROMAddr[romptr+6] & 0xf0) >> 4); + SiS_Pr->SiS_RVBHRS2 = ROMAddr[romptr+8] | ((ROMAddr[romptr+9] & 0x0f) << 8); + if((SiS_Pr->SiS_RVBHRS2) && (modeflag & HalfDCLK)) { + SiS_Pr->SiS_RVBHRS2 = ((SiS_Pr->SiS_RVBHRS2 + 3) >> 1) - 3; + tempax = (ROMAddr[romptr+9] >> 4) & 0x07; + if(ROMAddr[romptr+9] & 0x80) SiS_Pr->SiS_RVBHRS2 -= tempax; + else SiS_Pr->SiS_RVBHRS2 += tempax; + } if(SiS_Pr->SiS_VGAHT) gotit = TRUE; else { SiS_Pr->SiS_LCDInfo |= DontExpandLCD; SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT; - SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT; - SiS_Pr->SiS_HT = SiS_Pr->PanelHT; - SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + SiS_Pr->SiS_RVBHRS2 = 0; gotit = TRUE; } #endif @@ -3530,28 +3496,30 @@ SiS_GetCRT2Data301(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, if(!gotit) { - SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex, - &CRT2Index,&ResIndex,HwInfo); + SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex, + &CRT2Index,&ResIndex); - switch(CRT2Index) { + switch(CRT2Index) { case Panel_1024x768 : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; case Panel_1024x768 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data; break; case Panel_1280x720 : case Panel_1280x720 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x720Data; break; case Panel_1280x768_2 : LCDPtr = SiS_Pr->SiS_ExtLCD1280x768_2Data; break; - case Panel_1280x768_2+ 32: LCDPtr = SiS_Pr->SiS_StLCD1280x768_2Data; break; + case Panel_1280x768_2+ 32: LCDPtr = SiS_Pr->SiS_StLCD1280x768_2Data; break; case Panel_1280x800 : case Panel_1280x800 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x800Data; break; case Panel_1280x800_2 : case Panel_1280x800_2+ 32: LCDPtr = SiS_Pr->SiS_LCD1280x800_2Data; break; + case Panel_1280x854 : + case Panel_1280x854 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x854Data; break; case Panel_1280x960 : case Panel_1280x960 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x960Data; break; - case Panel_1280x1024 : LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data; break; - case Panel_1280x1024 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; - case Panel_1400x1050 : LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data; break; - case Panel_1400x1050 + 32: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data; break; - case Panel_1600x1200 : LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data; break; - case Panel_1600x1200 + 32: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data; break; + case Panel_1280x1024 : LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data; break; + case Panel_1280x1024 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; + case Panel_1400x1050 : LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data; break; + case Panel_1400x1050 + 32: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data; break; + case Panel_1600x1200 : LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data; break; + case Panel_1600x1200 + 32: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data; break; case Panel_1680x1050 : case Panel_1680x1050 + 32: LCDPtr = SiS_Pr->SiS_LCD1680x1050Data; break; case 100 : LCDPtr = SiS_Pr->SiS_NoScaleData; break; @@ -3559,271 +3527,340 @@ SiS_GetCRT2Data301(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, case 200 : LCDPtr = SiS310_ExtCompaq1280x1024Data; break; case 201 : LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; #endif - default : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; - } + default : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; + } +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex); + xf86DrvMsg(0, X_INFO, "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex); +#endif #endif - SiS_Pr->SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX; - SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT; - SiS_Pr->SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT; - SiS_Pr->SiS_VGAVT = (LCDPtr+ResIndex)->VGAVT; - SiS_Pr->SiS_HT = (LCDPtr+ResIndex)->LCDHT; - SiS_Pr->SiS_VT = (LCDPtr+ResIndex)->LCDVT; + SiS_Pr->SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX; + SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT; + SiS_Pr->SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT; + SiS_Pr->SiS_VGAVT = (LCDPtr+ResIndex)->VGAVT; + SiS_Pr->SiS_HT = (LCDPtr+ResIndex)->LCDHT; + SiS_Pr->SiS_VT = (LCDPtr+ResIndex)->LCDVT; } tempax = SiS_Pr->PanelXRes; - tempbx = SiS_Pr->PanelYRes; + tempbx = SiS_Pr->PanelYRes; - if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { - if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { - if(HwInfo->jChipType < SIS_315H) { - if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560; - else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640; - } - } else { - if (SiS_Pr->SiS_VGAVDE == 357) tempbx = 527; - else if(SiS_Pr->SiS_VGAVDE == 420) tempbx = 620; - else if(SiS_Pr->SiS_VGAVDE == 525) tempbx = 775; - else if(SiS_Pr->SiS_VGAVDE == 600) tempbx = 775; - else if(SiS_Pr->SiS_VGAVDE == 350) tempbx = 560; - else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640; - } - } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x960) { - if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 700; - else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 800; - else if(SiS_Pr->SiS_VGAVDE == 1024) tempbx = 960; - } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { - if (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768; - else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800; - else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864; - } else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1024x768: + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + if(SiS_Pr->ChipType < SIS_315H) { + if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640; + } + } else { + if (SiS_Pr->SiS_VGAVDE == 357) tempbx = 527; + else if(SiS_Pr->SiS_VGAVDE == 420) tempbx = 620; + else if(SiS_Pr->SiS_VGAVDE == 525) tempbx = 775; + else if(SiS_Pr->SiS_VGAVDE == 600) tempbx = 775; + else if(SiS_Pr->SiS_VGAVDE == 350) tempbx = 560; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640; + } + break; + case Panel_1280x960: + if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 700; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 800; + else if(SiS_Pr->SiS_VGAVDE == 1024) tempbx = 960; + break; + case Panel_1280x1024: + if (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768; + else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800; + else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864; + break; + case Panel_1600x1200: if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { - if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 875; - else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 1000; - } - } + if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 875; + else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 1000; + } + break; + } - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - tempax = SiS_Pr->SiS_VGAHDE; - tempbx = SiS_Pr->SiS_VGAVDE; - } + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = SiS_Pr->SiS_VGAHDE; + tempbx = SiS_Pr->SiS_VGAVDE; + } - SiS_Pr->SiS_HDE = tempax; - SiS_Pr->SiS_VDE = tempbx; + SiS_Pr->SiS_HDE = tempax; + SiS_Pr->SiS_VDE = tempbx; } } } static void -SiS_GetCRT2Data(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +SiS_GetCRT2Data(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { - if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - } else { - if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { - /* Need LVDS Data for LCD on 301B-DH */ - SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - } else { - SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - } - } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } else { + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + /* Need LVDS Data for LCD on 301B-DH */ + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } else { + SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + } - } else { + } else { - SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); - } + } } /*********************************************/ /* GET LVDS DES (SKEW) DATA */ /*********************************************/ -static void -SiS_GetLVDSDesPtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, USHORT *PanelIndex, - USHORT *ResIndex, PSIS_HW_INFO HwInfo) +static const struct SiS_LVDSDes * +SiS_GetLVDSDesPtr(struct SiS_Private *SiS_Pr) { - USHORT modeflag; + const struct SiS_LVDSDes *PanelDesPtr = NULL; - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - } +#ifdef SIS300 + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_LCDTypeInfo == 4) { + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + PanelDesPtr = SiS_Pr->SiS_PanelType04_1a; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + PanelDesPtr = SiS_Pr->SiS_PanelType04_2a; + } + } else if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { + PanelDesPtr = SiS_Pr->SiS_PanelType04_1b; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + PanelDesPtr = SiS_Pr->SiS_PanelType04_2b; + } + } + } + } + } +#endif + return PanelDesPtr; +} - (*ResIndex) &= 0x1F; - (*PanelIndex) = 0; +static void +SiS_GetLVDSDesData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short modeflag, ResIndex; + const struct SiS_LVDSDes *PanelDesPtr = NULL; - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - (*PanelIndex) = 50; - if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) (*PanelIndex) += 2; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*PanelIndex) += 1; - /* Nothing special needed for SOverscan */ - /* PALM uses NTSC data, PALN uses PAL data */ - } - } + SiS_Pr->SiS_LCDHDES = 0; + SiS_Pr->SiS_LCDVDES = 0; + /* Some special cases */ if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - *PanelIndex = SiS_Pr->SiS_LCDTypeInfo; - if(HwInfo->jChipType >= SIS_661) { - /* As long as we don's use the BIOS tables, we - * need to convert the TypeInfo as for 315 series - */ - (*PanelIndex) = SiS_Pr->SiS_LCDResInfo - 1; - } - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - (*PanelIndex) += 16; - if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - (*PanelIndex) = 32; - if(modeflag & HalfDCLK) (*PanelIndex)++; + + /* Trumpion */ + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } } + return; } - } - if(SiS_Pr->SiS_SetFlag & SetDOSMode) { - if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) { - (*ResIndex) = 7; - if(HwInfo->jChipType < SIS_315H) { - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) (*ResIndex)++; - } + /* 640x480 on LVDS */ + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480 && SiS_Pr->SiS_LCDTypeInfo == 3) { + SiS_Pr->SiS_LCDHDES = 8; + if (SiS_Pr->SiS_VGAVDE >= 480) SiS_Pr->SiS_LCDVDES = 512; + else if(SiS_Pr->SiS_VGAVDE >= 400) SiS_Pr->SiS_LCDVDES = 436; + else if(SiS_Pr->SiS_VGAVDE >= 350) SiS_Pr->SiS_LCDVDES = 440; + return; + } } - } -} - -static void -SiS_GetLVDSDesData(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) -{ - USHORT modeflag; - USHORT PanelIndex,ResIndex; - const SiS_LVDSDesStruct *PanelDesPtr = NULL; - SiS_Pr->SiS_LCDHDES = 0; - SiS_Pr->SiS_LCDVDES = 0; + } /* LCD */ if( (SiS_Pr->UseCustomMode) || (SiS_Pr->SiS_LCDResInfo == Panel_Custom) || (SiS_Pr->SiS_CustomT == CUT_PANEL848) || - ((SiS_Pr->SiS_VBType & VB_SISVB) && - (SiS_Pr->SiS_LCDInfo & DontExpandLCD) && - (SiS_Pr->SiS_LCDInfo & LCDPass11)) ) { + (SiS_Pr->SiS_CustomT == CUT_PANEL856) || + (SiS_Pr->SiS_LCDInfo & LCDPass11) ) { return; } - if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(ModeNo <= 0x13) ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + else ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + + if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { #ifdef SIS315H if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - /* non-pass 1:1 only, see above */ - if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) { - SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) / 2); + /* non-pass 1:1 only, see above */ + if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) { + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) / 2); + } + if(SiS_Pr->SiS_VGAVDE != SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE) / 2); + } + } + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + switch(SiS_Pr->SiS_CustomT) { + case CUT_UNIWILL1024: + case CUT_UNIWILL10242: + case CUT_CLEVO1400: + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + break; + } + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1280x1024: + if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + break; + case Panel_1280x800: /* Verified for Averatec 6240 */ + case Panel_1280x800_2: /* Verified for Asus A4L */ + case Panel_1280x854: /* Not verified yet FIXME */ + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + break; + } + } +#endif + + } else { + + if((SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + + if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) { + if(ResIndex <= 3) SiS_Pr->SiS_LCDHDES = 256; + } + + } else if((PanelDesPtr = SiS_GetLVDSDesPtr(SiS_Pr))) { + + SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES; + SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES; + + } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + + if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) { + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) / 2); } if(SiS_Pr->SiS_VGAVDE != SiS_Pr->PanelYRes) { SiS_Pr->SiS_LCDVDES = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE) / 2); - } - } - if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { - switch(SiS_Pr->SiS_CustomT) { - case CUT_UNIWILL1024: - case CUT_UNIWILL10242: - case CUT_CLEVO1400: - if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + } else { + if(SiS_Pr->ChipType < SIS_315H) { SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } else { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_800x600: + case Panel_1024x768: + case Panel_1280x1024: + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT; + break; + case Panel_1400x1050: + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + break; + } } - break; } - if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { - if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) { - SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + + } else { + + if(SiS_Pr->ChipType < SIS_315H) { +#ifdef SIS300 + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_800x600: + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } else { + SiS_Pr->SiS_LCDHDES = SiS_Pr->PanelHT + 3; + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT; + if(SiS_Pr->SiS_VGAVDE == 400) SiS_Pr->SiS_LCDVDES -= 2; + else SiS_Pr->SiS_LCDVDES -= 4; + } + break; + case Panel_1024x768: + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } else { + SiS_Pr->SiS_LCDHDES = SiS_Pr->PanelHT - 1; + if(SiS_Pr->SiS_VGAVDE <= 400) SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 8; + if(SiS_Pr->SiS_VGAVDE <= 350) SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 12; + } + break; + case Panel_1024x600: + default: + if( (SiS_Pr->SiS_VGAHDE == SiS_Pr->PanelXRes) && + (SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) ) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } else { + SiS_Pr->SiS_LCDHDES = SiS_Pr->PanelHT - 1; + } + break; + } + + switch(SiS_Pr->SiS_LCDTypeInfo) { + case 1: + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0; + break; + case 3: /* 640x480 only? */ + SiS_Pr->SiS_LCDHDES = 8; + if (SiS_Pr->SiS_VGAVDE >= 480) SiS_Pr->SiS_LCDVDES = 512; + else if(SiS_Pr->SiS_VGAVDE >= 400) SiS_Pr->SiS_LCDVDES = 436; + else if(SiS_Pr->SiS_VGAVDE >= 350) SiS_Pr->SiS_LCDVDES = 440; + break; + } +#endif + } else { +#ifdef SIS315H + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1024x768: + case Panel_1280x1024: + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + break; + case Panel_320x240_1: + case Panel_320x240_2: + case Panel_320x240_3: + SiS_Pr->SiS_LCDVDES = 524; + break; } +#endif } } -#endif - - } else { - - SiS_GetLVDSDesPtr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, - &PanelIndex, &ResIndex, HwInfo); - - switch(PanelIndex) { - case 0: PanelDesPtr = SiS_Pr->SiS_PanelType00_1; break; /* --- */ - case 1: PanelDesPtr = SiS_Pr->SiS_PanelType01_1; break; - case 2: PanelDesPtr = SiS_Pr->SiS_PanelType02_1; break; - case 3: PanelDesPtr = SiS_Pr->SiS_PanelType03_1; break; - case 4: PanelDesPtr = SiS_Pr->SiS_PanelType04_1; break; - case 5: PanelDesPtr = SiS_Pr->SiS_PanelType05_1; break; - case 6: PanelDesPtr = SiS_Pr->SiS_PanelType06_1; break; - case 7: PanelDesPtr = SiS_Pr->SiS_PanelType07_1; break; - case 8: PanelDesPtr = SiS_Pr->SiS_PanelType08_1; break; - case 9: PanelDesPtr = SiS_Pr->SiS_PanelType09_1; break; - case 10: PanelDesPtr = SiS_Pr->SiS_PanelType0a_1; break; - case 11: PanelDesPtr = SiS_Pr->SiS_PanelType0b_1; break; - case 12: PanelDesPtr = SiS_Pr->SiS_PanelType0c_1; break; - case 13: PanelDesPtr = SiS_Pr->SiS_PanelType0d_1; break; - case 14: PanelDesPtr = SiS_Pr->SiS_PanelType0e_1; break; - case 15: PanelDesPtr = SiS_Pr->SiS_PanelType0f_1; break; - case 16: PanelDesPtr = SiS_Pr->SiS_PanelType00_2; break; /* --- */ - case 17: PanelDesPtr = SiS_Pr->SiS_PanelType01_2; break; - case 18: PanelDesPtr = SiS_Pr->SiS_PanelType02_2; break; - case 19: PanelDesPtr = SiS_Pr->SiS_PanelType03_2; break; - case 20: PanelDesPtr = SiS_Pr->SiS_PanelType04_2; break; - case 21: PanelDesPtr = SiS_Pr->SiS_PanelType05_2; break; - case 22: PanelDesPtr = SiS_Pr->SiS_PanelType06_2; break; - case 23: PanelDesPtr = SiS_Pr->SiS_PanelType07_2; break; - case 24: PanelDesPtr = SiS_Pr->SiS_PanelType08_2; break; - case 25: PanelDesPtr = SiS_Pr->SiS_PanelType09_2; break; - case 26: PanelDesPtr = SiS_Pr->SiS_PanelType0a_2; break; - case 27: PanelDesPtr = SiS_Pr->SiS_PanelType0b_2; break; - case 28: PanelDesPtr = SiS_Pr->SiS_PanelType0c_2; break; - case 29: PanelDesPtr = SiS_Pr->SiS_PanelType0d_2; break; - case 30: PanelDesPtr = SiS_Pr->SiS_PanelType0e_2; break; - case 31: PanelDesPtr = SiS_Pr->SiS_PanelType0f_2; break; - case 32: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_1; break; /* pass 1:1 */ - case 33: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_2; break; - case 50: PanelDesPtr = SiS_Pr->SiS_CHTVUNTSCDesData; break; /* TV */ - case 51: PanelDesPtr = SiS_Pr->SiS_CHTVONTSCDesData; break; - case 52: PanelDesPtr = SiS_Pr->SiS_CHTVUPALDesData; break; - case 53: PanelDesPtr = SiS_Pr->SiS_CHTVOPALDesData; break; - default: return; - } - - SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES; - SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES; if((ModeNo <= 0x13) && (SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 632; - } else if(!(SiS_Pr->SiS_SetFlag & SetDOSMode)) { - if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) { - if(SiS_Pr->SiS_LCDResInfo >= Panel_1024x768) { - if(HwInfo->jChipType < SIS_315H) { + } else if(!(SiS_Pr->SiS_SetFlag & SetDOSMode)) { + if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) { + if(SiS_Pr->SiS_LCDResInfo >= Panel_1024x768) { + if(SiS_Pr->ChipType < SIS_315H) { if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320; } else { - if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) SiS_Pr->SiS_LCDHDES = 480; - if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 804; +#ifdef SIS315H + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) SiS_Pr->SiS_LCDHDES = 480; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 804; if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 704; - if(!(modeflag & HalfDCLK)) { - SiS_Pr->SiS_LCDHDES = 320; - if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 632; + if(!(modeflag & HalfDCLK)) { + SiS_Pr->SiS_LCDHDES = 320; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 632; if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 542; - } - } - } - } - } + } +#endif + } + } + } + } } } } @@ -3832,54 +3869,90 @@ SiS_GetLVDSDesData(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex, /* DISABLE VIDEO BRIDGE */ /*********************************************/ +#ifdef SIS315H +static int +SiS_HandlePWD(struct SiS_Private *SiS_Pr) +{ + int ret = 0; +#ifdef SET_PWD + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr = GetLCDStructPtr661_2(SiS_Pr); + unsigned char drivermode = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40; + unsigned short temp; + + if( (SiS_Pr->SiS_VBType & VB_SISPWD) && + (romptr) && + (SiS_Pr->SiS_PWDOffset) ) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2b,ROMAddr[romptr + SiS_Pr->SiS_PWDOffset + 0]); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2c,ROMAddr[romptr + SiS_Pr->SiS_PWDOffset + 1]); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2d,ROMAddr[romptr + SiS_Pr->SiS_PWDOffset + 2]); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2e,ROMAddr[romptr + SiS_Pr->SiS_PWDOffset + 3]); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2f,ROMAddr[romptr + SiS_Pr->SiS_PWDOffset + 4]); + temp = 0x00; + if((ROMAddr[romptr + 2] & (0x06 << 1)) && !drivermode) { + temp = 0x80; + ret = 1; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x27,0x7f,temp); +#ifdef SIS_XORG_XF86 +#ifdef TWDEBUG + xf86DrvMsg(0, 0, "Setting PWD %x\n", temp); +#endif +#endif + } +#endif + return ret; +} +#endif + /* NEVER use any variables (VBInfo), this will be called * from outside the context of modeswitch! * MUST call getVBType before calling this */ void -SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_DisableBridge(struct SiS_Private *SiS_Pr) { #ifdef SIS315H - USHORT tempah,pushax=0,modenum; + unsigned short tempah, pushax=0, modenum; #endif - USHORT temp=0; + unsigned short temp=0; if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { /* ===== For 30xB/LV ===== */ + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { /* ===== For 30xB/C/LV ===== */ - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 /* 300 series */ - if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE); + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE); } else { - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); } - SiS_PanelDelay(SiS_Pr, HwInfo, 3); + SiS_PanelDelay(SiS_Pr, 3); } if(SiS_Is301B(SiS_Pr)) { SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0x3f); SiS_ShortDelay(SiS_Pr,1); - } + } SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF); SiS_DisplayOff(SiS_Pr); SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); - SiS_UnLockCRT2(SiS_Pr,HwInfo); - if(!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { + SiS_UnLockCRT2(SiS_Pr); + if(!(SiS_Pr->SiS_VBType & VB_SISLVDS)) { SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80); SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); } - if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) || - (!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) ) { - SiS_PanelDelay(SiS_Pr, HwInfo, 2); - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); + if( (!(SiS_CRT2IsLCD(SiS_Pr))) || + (!(SiS_CR36BIOSWord23d(SiS_Pr))) ) { + SiS_PanelDelay(SiS_Pr, 2); + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); } else { - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04); } } @@ -3889,130 +3962,127 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) #ifdef SIS315H /* 315 series */ + int didpwd = 0; BOOLEAN custom1 = ((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) ? TRUE : FALSE; modenum = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34) & 0x7f; - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { #ifdef SET_EMI - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_Pr->SiS_VBType & VB_SISEMI) { if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) { - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); } } #endif - if( (modenum <= 0x13) || - (SiS_IsVAMode(SiS_Pr,HwInfo)) || - (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ) { - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE); - if(custom1) SiS_PanelDelay(SiS_Pr, HwInfo, 3); + + didpwd = SiS_HandlePWD(SiS_Pr); + + if( (modenum <= 0x13) || + (SiS_IsVAMode(SiS_Pr)) || + (!(SiS_IsDualEdge(SiS_Pr))) ) { + if(!didpwd) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xfe); + if(custom1) SiS_PanelDelay(SiS_Pr, 3); + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xfc); + } } if(!custom1) { SiS_DDC2Delay(SiS_Pr,0xff00); SiS_DDC2Delay(SiS_Pr,0xe000); - SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00); - pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06); + SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00); + pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06); if(IS_SIS740) { SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3); } - SiS_PanelDelay(SiS_Pr, HwInfo, 3); + SiS_PanelDelay(SiS_Pr, 3); } - } + } - if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) { - if(HwInfo->jChipType < SIS_340) { - tempah = 0xef; - if(SiS_IsVAMode(SiS_Pr,HwInfo)) tempah = 0xf7; - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah); - } + if(!(SiS_IsNotM650orLater(SiS_Pr))) { + /* if(SiS_Pr->ChipType < SIS_340) {*/ + tempah = 0xef; + if(SiS_IsVAMode(SiS_Pr)) tempah = 0xf7; + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah); + /*}*/ } - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,~0x10); } tempah = 0x3f; - if(SiS_IsDualEdge(SiS_Pr,HwInfo)) { + if(SiS_IsDualEdge(SiS_Pr)) { tempah = 0x7f; - if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) tempah = 0xbf; + if(!(SiS_IsVAMode(SiS_Pr))) tempah = 0xbf; } SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah); - if((SiS_IsVAMode(SiS_Pr,HwInfo)) || - ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) { + if((SiS_IsVAMode(SiS_Pr)) || + ((SiS_Pr->SiS_VBType & VB_SISLVDS) && (modenum <= 0x13))) { SiS_DisplayOff(SiS_Pr); - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - SiS_PanelDelay(SiS_Pr, HwInfo, 2); + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_PanelDelay(SiS_Pr, 2); } SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF); } - if((!(SiS_IsVAMode(SiS_Pr,HwInfo))) || - ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) { + if((!(SiS_IsVAMode(SiS_Pr))) || + ((SiS_Pr->SiS_VBType & VB_SISLVDS) && (modenum <= 0x13))) { - if(!(SiS_IsDualEdge(SiS_Pr,HwInfo))) { + if(!(SiS_IsDualEdge(SiS_Pr))) { SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf); SiS_DisplayOff(SiS_Pr); } SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80); - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - SiS_PanelDelay(SiS_Pr, HwInfo, 2); + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_PanelDelay(SiS_Pr, 2); } SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10); SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp); } - if(SiS_IsNotM650orLater(SiS_Pr,HwInfo)) { + if(SiS_IsNotM650orLater(SiS_Pr)) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); } - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - - if(!custom1) { - - if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) { - if(!(SiS_CRT2IsLCD(SiS_Pr,HwInfo))) { - if(!(SiS_IsDualEdge(SiS_Pr,HwInfo))) { - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); - } - } - } - - SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax); + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) { - SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 20); - } - } + if( (!(SiS_IsVAMode(SiS_Pr))) && + (!(SiS_CRT2IsLCD(SiS_Pr))) && + (!(SiS_IsDualEdge(SiS_Pr))) ) { - } else { + if(custom1) SiS_PanelDelay(SiS_Pr, 2); + if(!didpwd) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); + } + if(custom1) SiS_PanelDelay(SiS_Pr, 4); + } - if((SiS_IsVAMode(SiS_Pr,HwInfo)) || - (!(SiS_IsDualEdge(SiS_Pr,HwInfo)))) { - if((!(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo))) || - (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo)))) { - SiS_PanelDelay(SiS_Pr, HwInfo, 2); - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); - SiS_PanelDelay(SiS_Pr, HwInfo, 4); + if(!custom1) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax); + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + if(SiS_IsVAorLCD(SiS_Pr)) { + SiS_PanelDelayLoop(SiS_Pr, 3, 20); } } - } - } + + } #endif /* SIS315H */ @@ -4020,36 +4090,36 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } else { /* ============ For 301 ================ */ - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 - if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); - SiS_PanelDelay(SiS_Pr, HwInfo, 3); + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, 3); } #endif } - SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF); /* disable VB */ - SiS_DisplayOff(SiS_Pr); + SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF); /* disable VB */ + SiS_DisplayOff(SiS_Pr); - if(HwInfo->jChipType >= SIS_315H) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80); + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80); } - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); /* disable lock mode */ + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); /* disable lock mode */ - if(HwInfo->jChipType >= SIS_315H) { - temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10); + if(SiS_Pr->ChipType >= SIS_315H) { + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10); SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp); } else { #ifdef SIS300 - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); /* disable CRT2 */ - if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) || - (!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) ) { - SiS_PanelDelay(SiS_Pr, HwInfo, 2); - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); /* disable CRT2 */ + if( (!(SiS_CRT2IsLCD(SiS_Pr))) || + (!(SiS_CR36BIOSWord23d(SiS_Pr))) ) { + SiS_PanelDelay(SiS_Pr, 2); + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04); } #endif } @@ -4058,34 +4128,34 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } else { /* ============ For LVDS =============*/ - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 /* 300 series */ if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { - SiS_SetCH700x(SiS_Pr,0x090E); + SiS_SetCH700x(SiS_Pr,0x0E,0x09); } - if(HwInfo->jChipType == SIS_730) { + if(SiS_Pr->ChipType == SIS_730) { if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x08)) { - SiS_WaitVBRetrace(SiS_Pr,HwInfo); + SiS_WaitVBRetrace(SiS_Pr); } - if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); - SiS_PanelDelay(SiS_Pr, HwInfo, 3); + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, 3); } } else { if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x08)) { if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) { - if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { - SiS_WaitVBRetrace(SiS_Pr,HwInfo); + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_WaitVBRetrace(SiS_Pr); if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x1c)) { SiS_DisplayOff(SiS_Pr); - } - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); - SiS_PanelDelay(SiS_Pr, HwInfo, 3); - } - } + } + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, 3); + } + } } } @@ -4094,14 +4164,14 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); - SiS_UnLockCRT2(SiS_Pr,HwInfo); + SiS_UnLockCRT2(SiS_Pr); SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80); SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); - if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) || - (!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) ) { - SiS_PanelDelay(SiS_Pr, HwInfo, 2); - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); + if( (!(SiS_CRT2IsLCD(SiS_Pr))) || + (!(SiS_CR36BIOSWord23d(SiS_Pr))) ) { + SiS_PanelDelay(SiS_Pr, 2); + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04); } #endif /* SIS300 */ @@ -4110,113 +4180,113 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) #ifdef SIS315H /* 315 series */ - if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) { - if(HwInfo->jChipType < SIS_340) { - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,~0x18); - } - } + if(!(SiS_IsNotM650orLater(SiS_Pr))) { + /*if(SiS_Pr->ChipType < SIS_340) { */ /* XGI needs this */ + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,~0x18); + /* } */ + } if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { temp = SiS_GetCH701x(SiS_Pr,0x61); if(temp < 1) { - SiS_SetCH701x(SiS_Pr,0xac76); - SiS_SetCH701x(SiS_Pr,0x0066); + SiS_SetCH701x(SiS_Pr,0x76,0xac); + SiS_SetCH701x(SiS_Pr,0x66,0x00); } - if( (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || - (SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo)) ) { - SiS_SetCH701x(SiS_Pr,0x3e49); + if( (!(SiS_IsDualEdge(SiS_Pr))) || + (SiS_IsTVOrYPbPrOrScart(SiS_Pr)) ) { + SiS_SetCH701x(SiS_Pr,0x49,0x3e); } } - if( (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || - (SiS_IsVAMode(SiS_Pr,HwInfo)) ) { + if( (!(SiS_IsDualEdge(SiS_Pr))) || + (SiS_IsVAMode(SiS_Pr)) ) { SiS_Chrontel701xBLOff(SiS_Pr); - SiS_Chrontel701xOff(SiS_Pr,HwInfo); + SiS_Chrontel701xOff(SiS_Pr); } - if(HwInfo->jChipType != SIS_740) { - if( (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || - (SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo)) ) { - SiS_SetCH701x(SiS_Pr,0x0149); - } + if(SiS_Pr->ChipType != SIS_740) { + if( (!(SiS_IsDualEdge(SiS_Pr))) || + (SiS_IsTVOrYPbPrOrScart(SiS_Pr)) ) { + SiS_SetCH701x(SiS_Pr,0x49,0x01); + } } } if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); - SiS_PanelDelay(SiS_Pr, HwInfo, 3); + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x08); + SiS_PanelDelay(SiS_Pr, 3); } if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || - (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || - (!(SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo))) ) { + (!(SiS_IsDualEdge(SiS_Pr))) || + (!(SiS_IsTVOrYPbPrOrScart(SiS_Pr))) ) { SiS_DisplayOff(SiS_Pr); } if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || - (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || - (!(SiS_IsVAMode(SiS_Pr,HwInfo))) ) { + (!(SiS_IsDualEdge(SiS_Pr))) || + (!(SiS_IsVAMode(SiS_Pr))) ) { SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80); } - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); } SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF); if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || - (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || - (!(SiS_IsVAMode(SiS_Pr,HwInfo))) ) { + (!(SiS_IsDualEdge(SiS_Pr))) || + (!(SiS_IsVAMode(SiS_Pr))) ) { SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); } if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + if(SiS_CRT2IsLCD(SiS_Pr)) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf); - if(HwInfo->jChipType == SIS_550) { - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xbf); - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xef); + if(SiS_Pr->ChipType == SIS_550) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xbf); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xef); } } } else { - if(HwInfo->jChipType == SIS_740) { - if(SiS_IsLCDOrLCDA(SiS_Pr,HwInfo)) { - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf); + if(SiS_Pr->ChipType == SIS_740) { + if(SiS_IsLCDOrLCDA(SiS_Pr)) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf); } - } else if(SiS_IsVAMode(SiS_Pr,HwInfo)) { + } else if(SiS_IsVAMode(SiS_Pr)) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf); } } if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(SiS_IsDualEdge(SiS_Pr,HwInfo)) { + if(SiS_IsDualEdge(SiS_Pr)) { /* SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xff); */ } else { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb); } } - SiS_UnLockCRT2(SiS_Pr,HwInfo); + SiS_UnLockCRT2(SiS_Pr); - if(HwInfo->jChipType == SIS_550) { + if(SiS_Pr->ChipType == SIS_550) { SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80); /* DirectDVD PAL?*/ SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); /* VB clock / 4 ? */ } else if( (SiS_Pr->SiS_IF_DEF_CH70xx == 0) || - (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) || - (!(SiS_IsVAMode(SiS_Pr,HwInfo))) ) { + (!(SiS_IsDualEdge(SiS_Pr))) || + (!(SiS_IsVAMode(SiS_Pr))) ) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7); } if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { - SiS_PanelDelay(SiS_Pr, HwInfo, 2); - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); + if(SiS_CRT2IsLCD(SiS_Pr)) { + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 2); + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x04); } } } @@ -4237,78 +4307,81 @@ SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) * from outside the context of a mode switch! * MUST call getVBType before calling this */ -static void -SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +#ifdef SIS_LINUX_KERNEL +static +#endif +void +SiS_EnableBridge(struct SiS_Private *SiS_Pr) { - USHORT temp=0,tempah; + unsigned short temp=0, tempah; #ifdef SIS315H - USHORT temp1,pushax=0; + unsigned short temp1, pushax=0; BOOLEAN delaylong = FALSE; #endif if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { /* ====== For 301B et al ====== */ + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { /* ====== For 301B et al ====== */ - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 /* 300 series */ - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); } else if(SiS_Pr->SiS_VBType & VB_NoLCD) { - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x00); } - if(SiS_Pr->SiS_VBType & (VB_SIS301LV302LV | VB_NoLCD)) { - if(!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) { - SiS_PanelDelay(SiS_Pr, HwInfo, 0); + if(SiS_Pr->SiS_VBType & (VB_SISLVDS | VB_NoLCD)) { + if(!(SiS_CR36BIOSWord23d(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 0); } } } if((SiS_Pr->SiS_VBType & VB_NoLCD) && - (SiS_CRT2IsLCD(SiS_Pr, HwInfo))) { + (SiS_CRT2IsLCD(SiS_Pr))) { SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); /* Enable CRT2 */ - SiS_DisplayOn(SiS_Pr); - SiS_UnLockCRT2(SiS_Pr,HwInfo); + SiS_DisplayOn(SiS_Pr); + SiS_UnLockCRT2(SiS_Pr); SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF); if(SiS_BridgeInSlavemode(SiS_Pr)) { - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F); - } else { - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40); - } + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40); + } if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) { if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { - if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { - SiS_PanelDelay(SiS_Pr, HwInfo, 1); - } - SiS_WaitVBRetrace(SiS_Pr,HwInfo); - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); - } + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 1); + } + SiS_WaitVBRetrace(SiS_Pr); + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x00); + } } } else { temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF; /* lock mode */ - if(SiS_BridgeInSlavemode(SiS_Pr)) { - tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20; - } - SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); + if(SiS_BridgeInSlavemode(SiS_Pr)) { + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20; + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20); /* enable VB processor */ SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0); SiS_DisplayOn(SiS_Pr); - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { - if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { - SiS_PanelDelay(SiS_Pr, HwInfo, 1); - } + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 1); + } SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01); - } + } } } @@ -4322,31 +4395,32 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) #ifdef SIS315H /* 315 series */ #ifdef SET_EMI - UCHAR r30=0, r31=0, r32=0, r33=0, cr36=0; - /* USHORT emidelay=0; */ + unsigned char r30=0, r31=0, r32=0, r33=0, cr36=0; + int didpwd = 0; + /* unsigned short emidelay=0; */ #endif - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef); #ifdef SET_EMI - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_Pr->SiS_VBType & VB_SISEMI) { SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); } #endif } - if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) { - if(HwInfo->jChipType < SIS_340) { + if(!(SiS_IsNotM650orLater(SiS_Pr))) { + /*if(SiS_Pr->ChipType < SIS_340) { */ tempah = 0x10; - if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) { - if(SiS_TVEnabled(SiS_Pr, HwInfo)) tempah = 0x18; - else tempah = 0x08; + if(SiS_LCDAEnabled(SiS_Pr)) { + if(SiS_TVEnabled(SiS_Pr)) tempah = 0x18; + else tempah = 0x08; } SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4c,tempah); - } + /*}*/ } - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00); SiS_DisplayOff(SiS_Pr); @@ -4355,42 +4429,51 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3); } - if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) { - if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) { - SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 2); - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); - SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 2); - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - SiS_GenericDelay(SiS_Pr, 0x4500); + didpwd = SiS_HandlePWD(SiS_Pr); + + if(SiS_IsVAorLCD(SiS_Pr)) { + if(!didpwd) { + if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) { + SiS_PanelDelayLoop(SiS_Pr, 3, 2); + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); + SiS_PanelDelayLoop(SiS_Pr, 3, 2); + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_GenericDelay(SiS_Pr, 17664); + } + } + } else { + SiS_PanelDelayLoop(SiS_Pr, 3, 2); + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_GenericDelay(SiS_Pr, 17664); } } } if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40)) { - SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10); + SiS_PanelDelayLoop(SiS_Pr, 3, 10); delaylong = TRUE; } } - if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) { + if(!(SiS_IsVAMode(SiS_Pr))) { - temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF; + temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF; if(SiS_BridgeInSlavemode(SiS_Pr)) { - tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - if(!(tempah & SetCRT2ToRAMDAC)) { - if(!(SiS_LCDAEnabled(SiS_Pr, HwInfo))) temp |= 0x20; + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(!(tempah & SetCRT2ToRAMDAC)) { + if(!(SiS_LCDAEnabled(SiS_Pr))) temp |= 0x20; } - } - SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); /* enable CRT2 */ SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80); - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - SiS_PanelDelay(SiS_Pr, HwInfo, 2); + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + SiS_PanelDelay(SiS_Pr, 2); } } else { @@ -4402,38 +4485,48 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20); SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80); + if(SiS_Pr->SiS_VBType & VB_SISPOWER) { + if( (SiS_LCDAEnabled(SiS_Pr)) || + (SiS_CRT2IsLCD(SiS_Pr)) ) { + /* Enable "LVDS PLL power on" (even on 301C) */ + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x2a,0x7f); + /* Enable "LVDS Driver Power on" (even on 301C) */ + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x7f); + } + } + tempah = 0xc0; - if(SiS_IsDualEdge(SiS_Pr, HwInfo)) { + if(SiS_IsDualEdge(SiS_Pr)) { tempah = 0x80; - if(!(SiS_IsVAMode(SiS_Pr, HwInfo))) tempah = 0x40; + if(!(SiS_IsVAMode(SiS_Pr))) tempah = 0x40; } - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah); + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah); - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { - SiS_PanelDelay(SiS_Pr, HwInfo, 2); + SiS_PanelDelay(SiS_Pr, 2); SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1f,0x10); SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80); if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) { #ifdef SET_EMI - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); - SiS_GenericDelay(SiS_Pr, 0x500); + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); + SiS_GenericDelay(SiS_Pr, 2048); } #endif SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c); - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_Pr->SiS_VBType & VB_SISEMI) { #ifdef SET_EMI cr36 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); if(SiS_Pr->SiS_ROMNew) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo); + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr = GetLCDStructPtr661_2(SiS_Pr); if(romptr) { - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20); /* Reset */ + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20); /* Reset */ SiS_Pr->EMI_30 = 0; SiS_Pr->EMI_31 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 0]; SiS_Pr->EMI_32 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 1]; @@ -4511,21 +4604,21 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) if(!SiS_Pr->OverruleEMI) { #ifdef COMPAL_HACK if(SiS_Pr->SiS_CustomT == CUT_COMPAL1400_2) { - if((cr36 & 0x0f) == 0x09) { + if((cr36 & 0x0f) == 0x09) { r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x00; } } #endif #ifdef COMPAQ_HACK if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { - if((cr36 & 0x0f) == 0x03) { + if((cr36 & 0x0f) == 0x03) { r30 = 0x20; r31 = 0x12; r32 = 0xd0; r33 = 0x6b; } } #endif #ifdef ASUS_HACK if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { - if((cr36 & 0x0f) == 0x02) { + if((cr36 & 0x0f) == 0x02) { /* r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x33; */ /* rev 2 */ /* r30 = 0x20; r31 = 0x05; r32 = 0x60; r33 = 0x33; */ /* rev 3 */ /* r30 = 0x60; r31 = 0x0d; r32 = 0x70; r33 = 0x40; */ /* rev 4 */ @@ -4533,11 +4626,11 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } } #endif - } + } if(!(SiS_Pr->OverruleEMI && (!r30) && (!r31) && (!r32) && (!r33))) { SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20); /* Reset */ - SiS_GenericDelay(SiS_Pr, 0x500); + SiS_GenericDelay(SiS_Pr, 2048); } SiS_SetReg(SiS_Pr->SiS_Part4Port,0x31,r31); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x32,r32); @@ -4547,36 +4640,44 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); #ifdef SET_EMI - if( (SiS_LCDAEnabled(SiS_Pr, HwInfo)) || - (SiS_CRT2IsLCD(SiS_Pr, HwInfo)) ) { - if(r30 & 0x40) { - SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 5); + if( (SiS_LCDAEnabled(SiS_Pr)) || + (SiS_CRT2IsLCD(SiS_Pr)) ) { + if(r30 & 0x40) { + /*SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x2a,0x80);*/ + SiS_PanelDelayLoop(SiS_Pr, 3, 5); if(delaylong) { - SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 5); + SiS_PanelDelayLoop(SiS_Pr, 3, 5); delaylong = FALSE; } - SiS_WaitVBRetrace(SiS_Pr,HwInfo); + SiS_WaitVBRetrace(SiS_Pr); + SiS_WaitVBRetrace(SiS_Pr); if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { - SiS_GenericDelay(SiS_Pr, 0x500); + SiS_GenericDelay(SiS_Pr, 1280); } - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40); /* Enable */ - } + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40); /* Enable */ + /*SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x2a,0x7f);*/ + } } #endif } } - if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { - if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) { - SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10); + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + if(SiS_IsVAorLCD(SiS_Pr)) { + SiS_PanelDelayLoop(SiS_Pr, 3, 10); if(delaylong) { - SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10); + SiS_PanelDelayLoop(SiS_Pr, 3, 10); } - SiS_WaitVBRetrace(SiS_Pr,HwInfo); - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - SiS_GenericDelay(SiS_Pr, 0x500); + SiS_WaitVBRetrace(SiS_Pr); + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_GenericDelay(SiS_Pr, 2048); + SiS_WaitVBRetrace(SiS_Pr); + } + if(!didpwd) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01); + } else { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x03); } - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01); } } @@ -4586,7 +4687,7 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } - if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); } @@ -4596,26 +4697,26 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } else { /* ============ For 301 ================ */ - if(HwInfo->jChipType < SIS_315H) { - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); - SiS_PanelDelay(SiS_Pr, HwInfo, 0); + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x00); + SiS_PanelDelay(SiS_Pr, 0); } } temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF; /* lock mode */ if(SiS_BridgeInSlavemode(SiS_Pr)) { - tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20; + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); + if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20; } SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); /* enable CRT2 */ - if(HwInfo->jChipType >= SIS_315H) { - temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E); - if(!(temp & 0x80)) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80); /* BVBDOENABLE=1 */ + if(SiS_Pr->ChipType >= SIS_315H) { + temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E); + if(!(temp & 0x80)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80); /* BVBDOENABLE=1 */ } } @@ -4623,15 +4724,15 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) SiS_VBLongWait(SiS_Pr); SiS_DisplayOn(SiS_Pr); - if(HwInfo->jChipType >= SIS_315H) { - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); + if(SiS_Pr->ChipType >= SIS_315H) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); } SiS_VBLongWait(SiS_Pr); - if(HwInfo->jChipType < SIS_315H) { - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - SiS_PanelDelay(SiS_Pr, HwInfo, 1); - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + SiS_PanelDelay(SiS_Pr, 1); + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x00); } } @@ -4639,49 +4740,49 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } else { /* =================== For LVDS ================== */ - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 /* 300 series */ - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - if(HwInfo->jChipType == SIS_730) { - SiS_PanelDelay(SiS_Pr, HwInfo, 1); - SiS_PanelDelay(SiS_Pr, HwInfo, 1); - SiS_PanelDelay(SiS_Pr, HwInfo, 1); + if(SiS_CRT2IsLCD(SiS_Pr)) { + if(SiS_Pr->ChipType == SIS_730) { + SiS_PanelDelay(SiS_Pr, 1); + SiS_PanelDelay(SiS_Pr, 1); + SiS_PanelDelay(SiS_Pr, 1); } - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); - if(!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) { - SiS_PanelDelay(SiS_Pr, HwInfo, 0); + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x00); + if(!(SiS_CR36BIOSWord23d(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 0); } } SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); SiS_DisplayOn(SiS_Pr); - SiS_UnLockCRT2(SiS_Pr,HwInfo); + SiS_UnLockCRT2(SiS_Pr); SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF); if(SiS_BridgeInSlavemode(SiS_Pr)) { - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F); } else { - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40); } if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { - if(!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) { - SiS_WaitVBRetrace(SiS_Pr, HwInfo); - SiS_SetCH700x(SiS_Pr,0x0B0E); - } + if(!(SiS_CRT2IsLCD(SiS_Pr))) { + SiS_WaitVBRetrace(SiS_Pr); + SiS_SetCH700x(SiS_Pr,0x0E,0x0B); + } } - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) { - if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { - if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { - SiS_PanelDelay(SiS_Pr, HwInfo, 1); - SiS_PanelDelay(SiS_Pr, HwInfo, 1); - } - SiS_WaitVBRetrace(SiS_Pr, HwInfo); - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); - } + if(SiS_CRT2IsLCD(SiS_Pr)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) { + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) { + if(!(SiS_CR36BIOSWord23b(SiS_Pr))) { + SiS_PanelDelay(SiS_Pr, 1); + SiS_PanelDelay(SiS_Pr, 1); + } + SiS_WaitVBRetrace(SiS_Pr); + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x00); + } } } @@ -4691,94 +4792,94 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) #ifdef SIS315H /* 315 series */ - if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) { - if(HwInfo->jChipType < SIS_340) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,0x18); - } + if(!(SiS_IsNotM650orLater(SiS_Pr))) { + /*if(SiS_Pr->ChipType < SIS_340) {*/ /* XGI needs this */ + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,0x18); + /*}*/ } if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); - SiS_PanelDelay(SiS_Pr, HwInfo, 0); - } + if(SiS_CRT2IsLCD(SiS_Pr)) { + SiS_SetRegSR11ANDOR(SiS_Pr,0xFB,0x00); + SiS_PanelDelay(SiS_Pr, 0); + } } SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); - SiS_UnLockCRT2(SiS_Pr,HwInfo); + SiS_UnLockCRT2(SiS_Pr); SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7); if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - temp = SiS_GetCH701x(SiS_Pr,0x66); + temp = SiS_GetCH701x(SiS_Pr,0x66); temp &= 0x20; SiS_Chrontel701xBLOff(SiS_Pr); } - if(HwInfo->jChipType != SIS_550) { - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); + if(SiS_Pr->ChipType != SIS_550) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f); } - if(HwInfo->jChipType == SIS_740) { - if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - if(SiS_IsLCDOrLCDA(SiS_Pr, HwInfo)) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); + if(SiS_Pr->ChipType == SIS_740) { + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_IsLCDOrLCDA(SiS_Pr)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); } } } temp1 = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E); if(!(temp1 & 0x80)) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80); } if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - if(temp) { - SiS_Chrontel701xBLOn(SiS_Pr, HwInfo); + if(temp) { + SiS_Chrontel701xBLOn(SiS_Pr); } } if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { + if(SiS_CRT2IsLCD(SiS_Pr)) { SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); - if(HwInfo->jChipType == SIS_550) { + if(SiS_Pr->ChipType == SIS_550) { SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x40); SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x10); } } - } else if(SiS_IsVAMode(SiS_Pr,HwInfo)) { - if(HwInfo->jChipType != SIS_740) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); + } else if(SiS_IsVAMode(SiS_Pr)) { + if(SiS_Pr->ChipType != SIS_740) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20); } } - if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f); } if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - if(SiS_IsTVOrYPbPrOrScart(SiS_Pr,HwInfo)) { - SiS_Chrontel701xOn(SiS_Pr,HwInfo); - } - if( (SiS_IsVAMode(SiS_Pr,HwInfo)) || - (SiS_IsLCDOrLCDA(SiS_Pr,HwInfo)) ) { - SiS_ChrontelDoSomething1(SiS_Pr,HwInfo); - } + if(SiS_IsTVOrYPbPrOrScart(SiS_Pr)) { + SiS_Chrontel701xOn(SiS_Pr); + } + if( (SiS_IsVAMode(SiS_Pr)) || + (SiS_IsLCDOrLCDA(SiS_Pr)) ) { + SiS_ChrontelDoSomething1(SiS_Pr); + } } if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { - if( (SiS_IsVAMode(SiS_Pr,HwInfo)) || - (SiS_IsLCDOrLCDA(SiS_Pr,HwInfo)) ) { - SiS_Chrontel701xBLOn(SiS_Pr, HwInfo); - SiS_ChrontelInitTVVSync(SiS_Pr,HwInfo); - } - } + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + if( (SiS_IsVAMode(SiS_Pr)) || + (SiS_IsLCDOrLCDA(SiS_Pr)) ) { + SiS_Chrontel701xBLOn(SiS_Pr); + SiS_ChrontelInitTVVSync(SiS_Pr); + } + } } else if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { - if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { - if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - SiS_PanelDelay(SiS_Pr, HwInfo, 1); - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); + if(!(SiS_WeHaveBacklightCtrl(SiS_Pr))) { + if(SiS_CRT2IsLCD(SiS_Pr)) { + SiS_PanelDelay(SiS_Pr, 1); + SiS_SetRegSR11ANDOR(SiS_Pr,0xF7,0x00); } } } @@ -4797,243 +4898,204 @@ SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /* Set CRT2 OFFSET / PITCH */ static void -SiS_SetCRT2Offset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RRTI, PSIS_HW_INFO HwInfo) +SiS_SetCRT2Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RRTI) { - USHORT offset; - UCHAR temp; + unsigned short offset; + unsigned char temp; - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) return; + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) return; - offset = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,RRTI,HwInfo); + offset = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,RRTI); - if((SiS_Pr->SiS_LCDResInfo == Panel_640x480_2) || - (SiS_Pr->SiS_LCDResInfo == Panel_640x480_3)) { - offset >>= 1; - } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(offset & 0xFF)); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,(offset >> 8)); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(offset & 0xFF)); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,(offset >> 8)); - temp = (UCHAR)(((offset >> 3) & 0xFF) + 1); - if(offset % 8) temp++; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,temp); + temp = (unsigned char)(((offset >> 3) & 0xFF) + 1); + if(offset & 0x07) temp++; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,temp); } /* Set CRT2 sync and PanelLink mode */ static void -SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT RefreshRateTableIndex, - PSIS_HW_INFO HwInfo) +SiS_SetCRT2Sync(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short RefreshRateTableIndex) { - USHORT tempah=0,tempbl,infoflag; + unsigned short tempah=0, tempbl, infoflag; - tempbl = 0xC0; + tempbl = 0xC0; - if(SiS_Pr->UseCustomMode) { - infoflag = SiS_Pr->CInfoFlag; - } else { - infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; - } + if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + } - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { /* LVDS */ + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { /* LVDS */ - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - tempah = 0; - } else if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_LCDInfo & LCDSync)) { - tempah = SiS_Pr->SiS_LCDInfo; - } else tempah = infoflag >> 8; - tempah &= 0xC0; - tempah |= 0x20; - if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || - (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { - tempah |= 0xf0; - } - if( (SiS_Pr->SiS_IF_DEF_FSTN) || - (SiS_Pr->SiS_IF_DEF_DSTN) || - (SiS_Pr->SiS_IF_DEF_TRUMPION) || - (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) { - tempah |= 0x30; - } - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - if(HwInfo->jChipType >= SIS_315H) { - tempah >>= 3; - tempah &= 0x18; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xE7,tempah); - /* Don't care about 12/18/24 bit mode - TV is via VGA, not PL */ - } else { - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,0xe0); - } - } else { - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); - } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + tempah = 0; + } else if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_LCDInfo & LCDSync)) { + tempah = SiS_Pr->SiS_LCDInfo; + } else tempah = infoflag >> 8; + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { + tempah |= 0xf0; + } + if( (SiS_Pr->SiS_IF_DEF_FSTN) || + (SiS_Pr->SiS_IF_DEF_DSTN) || + (SiS_Pr->SiS_IF_DEF_TRUMPION) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + (SiS_Pr->SiS_CustomT == CUT_PANEL856) ) { + tempah |= 0x30; + } + if( (SiS_Pr->SiS_IF_DEF_FSTN) || + (SiS_Pr->SiS_IF_DEF_DSTN) ) { + tempah &= ~0xc0; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->ChipType >= SIS_315H) { + tempah >>= 3; + tempah &= 0x18; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xE7,tempah); + /* Don't care about 12/18/24 bit mode - TV is via VGA, not PL */ + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,0xe0); + } + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + } - } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 /* ---- 300 series --- */ - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { /* 630 - 301B(-DH) */ + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { /* 630 - 301B(-DH) */ - tempah = infoflag >> 8; - tempbl = 0; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_LCDInfo & LCDSync) { - tempah = SiS_Pr->SiS_LCDInfo; - tempbl = (tempah >> 6) & 0x03; - } - } - tempah &= 0xC0; - tempah |= 0x20; - if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; - tempah |= 0xc0; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); - if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { - SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); - } + tempah = infoflag >> 8; + tempbl = 0; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_LCDInfo & LCDSync) { + tempah = SiS_Pr->SiS_LCDInfo; + tempbl = (tempah >> 6) & 0x03; + } + } + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + tempah |= 0xc0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } - } else { /* 630 - 301 */ + } else { /* 630 - 301 */ - tempah = infoflag >> 8; - tempah &= 0xC0; - tempah |= 0x20; - if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + tempah = ((infoflag >> 8) & 0xc0) | 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); - } + } #endif /* SIS300 */ - } else { + } else { #ifdef SIS315H /* ------- 315 series ------ */ - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { /* 315 - LVDS */ + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { /* 315 - LVDS */ - tempbl = 0; - if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) && - (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { - tempah = infoflag >> 8; - if(SiS_Pr->SiS_LCDInfo & LCDSync) { - tempbl = ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6); - } - } else if((SiS_Pr->SiS_CustomT == CUT_CLEVO1400) && - (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050)) { - tempah = infoflag >> 8; - tempbl = 0x03; - } else { - tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); - tempbl = (tempah >> 6) & 0x03; - tempbl |= 0x08; - if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempbl |= 0x04; - } - tempah &= 0xC0; - tempah |= 0x20; - if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) tempah |= 0xc0; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); - } - } + tempbl = 0; + if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) && + (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { + tempah = infoflag >> 8; + if(SiS_Pr->SiS_LCDInfo & LCDSync) { + tempbl = ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6); + } + } else if((SiS_Pr->SiS_CustomT == CUT_CLEVO1400) && + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050)) { + tempah = infoflag >> 8; + tempbl = 0x03; + } else { + tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); + tempbl = (tempah >> 6) & 0x03; + tempbl |= 0x08; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempbl |= 0x04; + } + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) tempah |= 0xc0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } + } - } else { /* 315 - TMDS */ + } else { /* 315 - TMDS */ - tempah = tempbl = infoflag >> 8; - if(!SiS_Pr->UseCustomMode) { - tempbl = 0; - if((SiS_Pr->SiS_VBType & VB_SIS301C) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { - if(ModeNo <= 0x13) { - tempah = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)); - } - } - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { - if(SiS_Pr->SiS_LCDInfo & LCDSync) { - tempah = SiS_Pr->SiS_LCDInfo; + tempah = tempbl = infoflag >> 8; + if(!SiS_Pr->UseCustomMode) { + tempbl = 0; + if((SiS_Pr->SiS_VBType & VB_SIS30xC) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + if(ModeNo <= 0x13) { + tempah = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)); + } + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(SiS_Pr->SiS_LCDInfo & LCDSync) { + tempah = SiS_Pr->SiS_LCDInfo; tempbl = (tempah >> 6) & 0x03; } - } - } - } - tempah &= 0xC0; - tempah |= 0x20; - if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; - if(SiS_Pr->SiS_VBType & VB_NoLCD) { - /* Imitate BIOS bug */ - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempah |= 0xc0; - } - if((SiS_Pr->SiS_VBType & VB_SIS301C) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { - tempah >>= 3; - tempah &= 0x18; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xe7,tempah); - } else { - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); - } - } - } + } + } + } + tempah &= 0xC0; + tempah |= 0x20; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + if(SiS_Pr->SiS_VBType & VB_NoLCD) { + /* Imitate BIOS bug */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempah |= 0xc0; + } + if((SiS_Pr->SiS_VBType & VB_SIS30xC) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempah >>= 3; + tempah &= 0x18; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xe7,tempah); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } + } + } - } + } #endif /* SIS315H */ } } } -/* Set CRT2 FIFO on 300/630/730 */ +/* Set CRT2 FIFO on 300/540/630/730 */ #ifdef SIS300 static void -SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,USHORT ModeNo, - PSIS_HW_INFO HwInfo) -{ - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT temp,index; - USHORT modeidindex,refreshratetableindex; - USHORT VCLK=0,MCLK,colorth=0,data2=0; - USHORT tempal, tempah, tempbx, tempcl, tempax; - USHORT CRT1ModeNo,CRT2ModeNo; - USHORT SelectRate_backup; - ULONG data,eax; - const UCHAR LatencyFactor[] = { - 97, 88, 86, 79, 77, 00, /*; 64 bit BQ=2 */ - 00, 87, 85, 78, 76, 54, /*; 64 bit BQ=1 */ - 97, 88, 86, 79, 77, 00, /*; 128 bit BQ=2 */ - 00, 79, 77, 70, 68, 48, /*; 128 bit BQ=1 */ - 80, 72, 69, 63, 61, 00, /*; 64 bit BQ=2 */ - 00, 70, 68, 61, 59, 37, /*; 64 bit BQ=1 */ - 86, 77, 75, 68, 66, 00, /*; 128 bit BQ=2 */ - 00, 68, 66, 59, 57, 37 /*; 128 bit BQ=1 */ - }; - const UCHAR LatencyFactor730[] = { - 69, 63, 61, - 86, 79, 77, - 103, 96, 94, - 120,113,111, - 137,130,128, /* <-- last entry, data below */ - 137,130,128, /* to avoid using illegal values */ - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - 137,130,128, - }; - const UCHAR ThLowB[] = { - 81, 4, 72, 6, 88, 8,120,12, - 55, 4, 54, 6, 66, 8, 90,12, - 42, 4, 45, 6, 55, 8, 75,12 - }; - const UCHAR ThTiming[] = { - 1, 2, 2, 3, 0, 1, 1, 2 +SiS_SetCRT2FIFO_300(struct SiS_Private *SiS_Pr,unsigned short ModeNo) +{ + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short temp, index, modeidindex, refreshratetableindex; + unsigned short VCLK = 0, MCLK, colorth = 0, data2 = 0; + unsigned short tempbx, tempcl, CRT1ModeNo, CRT2ModeNo, SelectRate_backup; + unsigned int data, pci50, pciA0; + static const unsigned char colortharray[] = { + 1, 1, 2, 2, 3, 4 }; SelectRate_backup = SiS_Pr->SiS_SelectCRT2Rate; @@ -5044,232 +5106,159 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,USHORT ModeNo, SiS_SearchModeID(SiS_Pr, &CRT1ModeNo, &modeidindex); SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); SiS_Pr->SiS_SelectCRT2Rate = 0; - refreshratetableindex = SiS_GetRatePtr(SiS_Pr, CRT1ModeNo, modeidindex, HwInfo); + refreshratetableindex = SiS_GetRatePtr(SiS_Pr, CRT1ModeNo, modeidindex); if(CRT1ModeNo >= 0x13) { - index = SiS_Pr->SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK; - index &= 0x3F; - VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ + /* Get VCLK */ + index = SiS_GetRefCRTVCLK(SiS_Pr, refreshratetableindex, SiS_Pr->SiS_UseWide); + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; - colorth = SiS_GetColorDepth(SiS_Pr,CRT1ModeNo,modeidindex); /* Get colordepth */ - colorth >>= 1; - if(!colorth) colorth++; + /* Get colordepth */ + colorth = SiS_GetColorDepth(SiS_Pr,CRT1ModeNo,modeidindex) >> 1; + if(!colorth) colorth++; } } else { CRT1ModeNo = 0xfe; - VCLK = SiS_Pr->CSRClock_CRT1; /* Get VCLK */ - data2 = (SiS_Pr->CModeFlag_CRT1 & ModeTypeMask) - 2; - switch(data2) { /* Get color depth */ - case 0 : colorth = 1; break; - case 1 : colorth = 1; break; - case 2 : colorth = 2; break; - case 3 : colorth = 2; break; - case 4 : colorth = 3; break; - case 5 : colorth = 4; break; - default: colorth = 2; - } + + /* Get VCLK */ + VCLK = SiS_Pr->CSRClock_CRT1; + + /* Get color depth */ + colorth = colortharray[((SiS_Pr->CModeFlag_CRT1 & ModeTypeMask) - 2)]; } if(CRT1ModeNo >= 0x13) { - if(HwInfo->jChipType == SIS_300) { - index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A); - } else { - index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A); - } - index &= 0x07; - MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK; /* Get MCLK */ + /* Get MCLK */ + if(SiS_Pr->ChipType == SIS_300) { + index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x3A); + } else { + index = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1A); + } + index &= 0x07; + MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK; - data2 = (colorth * VCLK) / MCLK; + temp = ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) >> 6) & 0x03) << 1; + if(!temp) temp++; + temp <<= 2; - temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); - temp = ((temp & 0x00FF) >> 6) << 1; - if(temp == 0) temp = 1; - temp <<= 2; - temp &= 0xff; + data2 = temp - ((colorth * VCLK) / MCLK); - data2 = temp - data2; + temp = (28 * 16) % data2; + data2 = (28 * 16) / data2; + if(temp) data2++; - if((28 * 16) % data2) { - data2 = (28 * 16) / data2; - data2++; - } else { - data2 = (28 * 16) / data2; - } + if(SiS_Pr->ChipType == SIS_300) { - if(HwInfo->jChipType == SIS_300) { - - tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x18); - tempah &= 0x62; - tempah >>= 1; - tempal = tempah; - tempah >>= 3; - tempal |= tempah; - tempal &= 0x07; - tempcl = ThTiming[tempal]; - tempbx = SiS_GetReg(SiS_Pr->SiS_P3c4,0x16); - tempbx >>= 6; - tempah = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); - tempah >>= 4; - tempah &= 0x0c; - tempbx |= tempah; - tempbx <<= 1; - tempal = ThLowB[tempbx + 1]; - tempal *= tempcl; - tempal += ThLowB[tempbx]; - data = tempal; - - } else if(HwInfo->jChipType == SIS_730) { - -#ifdef LINUX_KERNEL - SiS_SetRegLong(0xcf8,0x80000050); - eax = SiS_GetRegLong(0xcfc); + SiS_GetFIFOThresholdIndex300(SiS_Pr, &tempbx, &tempcl); + data = SiS_GetFIFOThresholdB300(tempbx, tempcl); + + } else { + +#ifdef SIS_LINUX_KERNEL + pci50 = sisfb_read_nbridge_pci_dword(SiS_Pr, 0x50); + pciA0 = sisfb_read_nbridge_pci_dword(SiS_Pr, 0xa0); #else - eax = pciReadLong(0x00000000, 0x50); + pci50 = pciReadLong(0x00000000, 0x50); + pciA0 = pciReadLong(0x00000000, 0xA0); #endif - tempal = (USHORT)(eax >> 8); - tempal &= 0x06; - tempal <<= 5; -#ifdef LINUX_KERNEL - SiS_SetRegLong(0xcf8,0x800000A0); - eax = SiS_GetRegLong(0xcfc); -#else - eax = pciReadLong(0x00000000, 0xA0); -#endif - temp = (USHORT)(eax >> 28); - temp &= 0x0F; - tempal |= temp; - - tempbx = tempal; /* BIOS BUG (2.04.5d, 2.04.6a use ah here, which is unset!) */ - tempbx = 0; /* -- do it like the BIOS anyway... */ - tempax = tempbx; - tempbx &= 0xc0; - tempbx >>= 6; - tempax &= 0x0f; - tempax *= 3; - tempbx += tempax; - - data = LatencyFactor730[tempbx]; - data += 15; - temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); - if(!(temp & 0x80)) data += 5; + if(SiS_Pr->ChipType == SIS_730) { - } else { + index = (unsigned short)(((pciA0 >> 28) & 0x0f) * 3); + index += (unsigned short)(((pci50 >> 9)) & 0x03); - index = 0; - temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); - if(temp & 0x0080) index += 12; + /* BIOS BUG (2.04.5d, 2.04.6a use ah here, which is unset!) */ + index = 0; /* -- do it like the BIOS anyway... */ -#ifdef LINUX_KERNEL - SiS_SetRegLong(0xcf8,0x800000A0); - eax = SiS_GetRegLong(0xcfc); -#else - /* We use pci functions X offers. We use tag 0, because - * we want to read/write to the host bridge (which is always - * 00:00.0 on 630, 730 and 540), not the VGA device. - */ - eax = pciReadLong(0x00000000, 0xA0); -#endif - temp = (USHORT)(eax >> 24); - if(!(temp&0x01)) index += 24; - -#ifdef LINUX_KERNEL - SiS_SetRegLong(0xcf8,0x80000050); - eax = SiS_GetRegLong(0xcfc); -#else - eax = pciReadLong(0x00000000, 0x50); -#endif - temp=(USHORT)(eax >> 24); - if(temp & 0x01) index += 6; + } else { - temp = (temp & 0x0F) >> 1; - index += temp; + pci50 >>= 24; + pciA0 >>= 24; - data = LatencyFactor[index]; - data += 15; - temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14); - if(!(temp & 0x80)) data += 5; - } + index = (pci50 >> 1) & 0x07; + + if(pci50 & 0x01) index += 6; + if(!(pciA0 & 0x01)) index += 24; + + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x80) index += 12; - data += data2; /* CRT1 Request Period */ + } - SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; - SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup; + data = SiS_GetLatencyFactor630(SiS_Pr, index) + 15; + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x80)) data += 5; - if(!SiS_Pr->UseCustomMode) { + } - CRT2ModeNo = ModeNo; - SiS_SearchModeID(SiS_Pr, &CRT2ModeNo, &modeidindex); + data += data2; /* CRT1 Request Period */ - refreshratetableindex = SiS_GetRatePtr(SiS_Pr, CRT2ModeNo, modeidindex, HwInfo); + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup; - index = SiS_GetVCLK2Ptr(SiS_Pr,CRT2ModeNo,modeidindex, - refreshratetableindex,HwInfo); - VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ + if(!SiS_Pr->UseCustomMode) { - if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { - if(SiS_Pr->SiS_UseROM) { - if(ROMAddr[0x220] & 0x01) { - VCLK = ROMAddr[0x229] | (ROMAddr[0x22a] << 8); - } - } - } + CRT2ModeNo = ModeNo; + SiS_SearchModeID(SiS_Pr, &CRT2ModeNo, &modeidindex); - } else { + refreshratetableindex = SiS_GetRatePtr(SiS_Pr, CRT2ModeNo, modeidindex); - CRT2ModeNo = 0xfe; - VCLK = SiS_Pr->CSRClock; /* Get VCLK */ + /* Get VCLK */ + index = SiS_GetVCLK2Ptr(SiS_Pr, CRT2ModeNo, modeidindex, refreshratetableindex); + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; - } + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x01) { + VCLK = ROMAddr[0x229] | (ROMAddr[0x22a] << 8); + } + } + } + + } else { + + /* Get VCLK */ + CRT2ModeNo = 0xfe; + VCLK = SiS_Pr->CSRClock; + + } - colorth = SiS_GetColorDepth(SiS_Pr,CRT2ModeNo,modeidindex); /* Get colordepth */ - colorth >>= 1; - if(!colorth) colorth++; + /* Get colordepth */ + colorth = SiS_GetColorDepth(SiS_Pr,CRT2ModeNo,modeidindex) >> 1; + if(!colorth) colorth++; - data = data * VCLK * colorth; - if(data % (MCLK << 4)) { - data = data / (MCLK << 4); - data++; - } else { - data = data / (MCLK << 4); - } + data = data * VCLK * colorth; + temp = data % (MCLK << 4); + data = data / (MCLK << 4); + if(temp) data++; - if(data <= 6) data = 6; - if(data > 0x14) data = 0x14; + if(data < 6) data = 6; + else if(data > 0x14) data = 0x14; - temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x01); - if(HwInfo->jChipType == SIS_300) { - if(data <= 0x0f) temp = (temp & (~0x1F)) | 0x13; - else temp = (temp & (~0x1F)) | 0x16; - if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { - temp = (temp & (~0x1F)) | 0x13; - } - } else { - if( ( (HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730) ) && - (HwInfo->jChipRevision >= 0x30) ) /* 630s or 730(s?) */ - { - temp = (temp & (~0x1F)) | 0x1b; - } else { - temp = (temp & (~0x1F)) | 0x16; - } - } - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0xe0,temp); + if(SiS_Pr->ChipType == SIS_300) { + temp = 0x16; + if((data <= 0x0f) || (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) + temp = 0x13; + } else { + temp = 0x16; + if(( (SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730) ) && + (SiS_Pr->ChipRevision >= 0x30)) + temp = 0x1b; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0xe0,temp); - if( (HwInfo->jChipType == SIS_630) && - (HwInfo->jChipRevision >= 0x30) ) /* 630s, NOT 730 */ - { - if(data > 0x13) data = 0x13; - } - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,0xe0,data); + if((SiS_Pr->ChipType == SIS_630) && + (SiS_Pr->ChipRevision >= 0x30)) { + if(data > 0x13) data = 0x13; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,0xe0,data); } else { /* If mode <= 0x13, we just restore everything */ - SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; - SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup; + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup; } } @@ -5278,10 +5267,10 @@ SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,USHORT ModeNo, /* Set CRT2 FIFO on 315/330 series */ #ifdef SIS315H static void -SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_SetCRT2FIFO_310(struct SiS_Private *SiS_Pr) { SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3B); - if( (HwInfo->jChipType == SIS_760) && + if( (SiS_Pr->ChipType == SIS_760) && (SiS_Pr->SiS_SysFlags & SF_760LFB) && (SiS_Pr->SiS_ModeType == Mode32Bpp) && (SiS_Pr->SiS_VGAHDE >= 1280) && @@ -5299,337 +5288,162 @@ SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } #endif -static USHORT -SiS_GetVGAHT2(SiS_Private *SiS_Pr) +static unsigned short +SiS_GetVGAHT2(struct SiS_Private *SiS_Pr) { - ULONG tempax,tempbx; + unsigned int tempax,tempbx; tempbx = (SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) * SiS_Pr->SiS_RVBHCMAX; tempax = (SiS_Pr->SiS_VT - SiS_Pr->SiS_VDE) * SiS_Pr->SiS_RVBHCFACT; tempax = (tempax * SiS_Pr->SiS_HT) / tempbx; - return((USHORT)tempax); + return (unsigned short)tempax; } /* Set Part 1 / SiS bridge slave mode */ static void -SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo,USHORT RefreshRateTableIndex) -{ - USHORT push1,push2; - USHORT tempax,tempbx,tempcx,temp; - USHORT resinfo,modeflag,xres=0; - unsigned char p1_7, p1_8; +SiS_SetGroup1_301(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short temp, modeflag, i, j, xres=0, VGAVDE; + static const unsigned short CRTranslation[] = { + /* CR0 CR1 CR2 CR3 CR4 CR5 CR6 CR7 */ + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + /* CR8 CR9 SR0A SR0B SR0C SR0D SR0E CR0F */ + 0x00, 0x0b, 0x17, 0x18, 0x19, 0x00, 0x1a, 0x00, + /* CR10 CR11 CR12 CR13 CR14 CR15 CR16 CR17 */ + 0x0c, 0x0d, 0x0e, 0x00, 0x0f, 0x10, 0x11, 0x00 + }; if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; } else if(SiS_Pr->UseCustomMode) { modeflag = SiS_Pr->CModeFlag; - resinfo = 0; xres = SiS_Pr->CHDisplay; } else { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes; } /* The following is only done if bridge is in slave mode: */ - if((HwInfo->jChipType >= SIS_661) && (ModeNo > 0x13)) { - if(xres >= 1600) { + if(SiS_Pr->ChipType >= SIS_315H) { + if(xres >= 1600) { /* BIOS: == 1600 */ SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x31,0x04); } } - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,0xff); /* set MAX HT */ + SiS_Pr->CHTotal = 8224; /* Max HT, 0x2020, results in 0x3ff in registers */ - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) modeflag |= Charx8Dot; - - if(modeflag & Charx8Dot) tempcx = 0x08; - else tempcx = 0x09; - - tempax = SiS_Pr->SiS_VGAHDE; /* 0x04 Horizontal Display End */ - if(modeflag & HalfDCLK) tempax >>= 1; - tempax = ((tempax / tempcx) - 1) & 0xff; - tempbx = tempax; - - temp = tempax; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x04,temp); + SiS_Pr->CHDisplay = SiS_Pr->SiS_VGAHDE; + if(modeflag & HalfDCLK) SiS_Pr->CHDisplay >>= 1; + SiS_Pr->CHBlankStart = SiS_Pr->CHDisplay; if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) { - temp += 2; - } - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if(resinfo == SIS_RI_800x600) temp -= 2; - } - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x05,temp); /* 0x05 Horizontal Display Start */ - - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x06,0x03); /* 0x06 Horizontal Blank end */ - - tempax = 0xFFFF; - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempax = SiS_GetVGAHT2(SiS_Pr); - if(tempax >= SiS_Pr->SiS_VGAHT) tempax = SiS_Pr->SiS_VGAHT; - if(modeflag & HalfDCLK) tempax >>= 1; - tempax = (tempax / tempcx) - 5; - tempcx = tempax; - - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - temp = tempcx - 1; - if(!(modeflag & HalfDCLK)) { - temp -= 6; - if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { - temp -= 2; - if(ModeNo > 0x13) temp -= 10; - } - } - } else { - tempcx = (tempcx + tempbx) >> 1; - temp = (tempcx & 0x00FF) + 2; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - temp--; - if(!(modeflag & HalfDCLK)) { - if((modeflag & Charx8Dot)) { - temp += 4; - if(SiS_Pr->SiS_VGAHDE >= 800) temp -= 6; - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_VGAHDE == 800) temp += 2; - } - } - } - } else { - if(!(modeflag & HalfDCLK)) { - temp -= 4; - if((SiS_Pr->SiS_LCDResInfo != Panel_1280x960) && - (SiS_Pr->SiS_LCDResInfo != Panel_1600x1200)) { - if(SiS_Pr->SiS_VGAHDE >= 800) { - temp -= 7; - if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_ModeType == ModeEGA) { - if(SiS_Pr->SiS_VGAVDE == 1024) { - temp += 15; - if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) - temp += 7; - } - } - } - if(SiS_Pr->SiS_LCDResInfo != Panel_1400x1050) { - if(SiS_Pr->SiS_VGAHDE >= 1280) { - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) temp += 28; - } - } - } - } - } - } + SiS_Pr->CHBlankStart += 16; } - p1_7 = temp; - p1_8 = 0x00; - - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { - if(ModeNo <= 0x01) { - p1_7 = 0x2a; - if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) p1_8 = 0x61; - else p1_8 = 0x41; - } else if(SiS_Pr->SiS_ModeType == ModeText) { - if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) p1_7 = 0x54; - else p1_7 = 0x55; - p1_8 = 0x00; - } else if(ModeNo <= 0x13) { - if(modeflag & HalfDCLK) { - if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { - p1_7 = 0x30; - p1_8 = 0x03; - } else { - p1_7 = 0x2f; - p1_8 = 0x02; - } - } else { - p1_7 = 0x5b; - p1_8 = 0x03; - } - } else if( ((HwInfo->jChipType >= SIS_315H) && - ((ModeNo == 0x50) || (ModeNo == 0x56) || (ModeNo == 0x53))) || - ((HwInfo->jChipType < SIS_315H) && - (resinfo == SIS_RI_320x200 || resinfo == SIS_RI_320x240)) ) { - if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { - p1_7 = 0x30, - p1_8 = 0x03; - } else { - p1_7 = 0x2f; - p1_8 = 0x03; - } - } - } + SiS_Pr->CHBlankEnd = 32; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(xres == 1600) SiS_Pr->CHBlankEnd += 80; } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p|TVSetYPbPr750p)) { - p1_7 = 0x63; - if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) p1_7 = 0x55; - } - if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { - if(!(modeflag & HalfDCLK)) { - p1_7 = 0xb2; - if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { - p1_7 = 0xab; - } - } - } else { - if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { - if(modeflag & HalfDCLK) p1_7 = 0x30; - } - } + temp = SiS_Pr->SiS_VGAHT - 96; + if(!(modeflag & HalfDCLK)) temp -= 32; + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x04); + temp |= ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x0b) & 0xc0) << 2); + temp -= 3; + temp <<= 3; + } else { + if(SiS_Pr->SiS_RVBHRS2) temp = SiS_Pr->SiS_RVBHRS2; } + SiS_Pr->CHSyncStart = temp; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,p1_7); /* 0x07 Horizontal Retrace Start */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,p1_8); /* 0x08 Horizontal Retrace End */ - - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x03); /* 0x18 SR08 (FIFO Threshold?) */ + SiS_Pr->CHSyncEnd = 0xffe8; /* results in 0x2000 in registers */ - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x19,0xF0); + SiS_Pr->CVTotal = 2049; /* Max VT, 0x0801, results in 0x7ff in registers */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,0xFF); /* 0x09 Set Max VT */ + VGAVDE = SiS_Pr->SiS_VGAVDE; + if (VGAVDE == 357) VGAVDE = 350; + else if(VGAVDE == 360) VGAVDE = 350; + else if(VGAVDE == 375) VGAVDE = 350; + else if(VGAVDE == 405) VGAVDE = 400; + else if(VGAVDE == 420) VGAVDE = 400; + else if(VGAVDE == 525) VGAVDE = 480; + else if(VGAVDE == 1056) VGAVDE = 1024; + SiS_Pr->CVDisplay = VGAVDE; - tempcx = 0x121; - tempbx = SiS_Pr->SiS_VGAVDE; /* 0x0E Vertical Display End */ - if (tempbx == 357) tempbx = 350; - else if(tempbx == 360) tempbx = 350; - else if(tempbx == 375) tempbx = 350; - else if(tempbx == 405) tempbx = 400; - else if(tempbx == 420) tempbx = 400; - else if(tempbx == 525) tempbx = 480; - push2 = tempbx; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { - if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { - if (tempbx == 350) tempbx += 5; - else if(tempbx == 480) tempbx += 5; - } - } - } - tempbx -= 2; - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,temp); /* 0x10 vertical Blank Start */ - - tempbx = push2; - tempbx--; - temp = tempbx & 0x00FF; -#if 0 - /* Missing code from 630/301B 2.04.5a and 650/302LV 1.10.6s (calles int 2f) */ - if(xxx()) { - if(temp == 0xdf) temp = 0xda; - } -#endif - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0E,temp); - - temp = 0; - if(modeflag & DoubleScanMode) temp |= 0x80; - if(HwInfo->jChipType >= SIS_661) { - if(tempbx & 0x0200) temp |= 0x20; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x0B,0x5F,temp); - if(tempbx & 0x0100) tempcx |= 0x000a; - if(tempbx & 0x0400) tempcx |= 0x1200; - } else { - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,temp); - if(tempbx & 0x0100) tempcx |= 0x0002; - if(tempbx & 0x0400) tempcx |= 0x0600; - } + SiS_Pr->CVBlankStart = SiS_Pr->CVDisplay; - if(tempbx & 0x0200) tempcx |= 0x0040; + SiS_Pr->CVBlankEnd = 1; + if(ModeNo == 0x3c) SiS_Pr->CVBlankEnd = 226; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x11,0x00); /* 0x11 Vertical Blank End */ + temp = (SiS_Pr->SiS_VGAVT - VGAVDE) >> 1; + SiS_Pr->CVSyncStart = VGAVDE + temp; - tempax = (SiS_Pr->SiS_VGAVT - tempbx) >> 2; + temp >>= 3; + SiS_Pr->CVSyncEnd = SiS_Pr->CVSyncStart + temp; - if((ModeNo > 0x13) || (HwInfo->jChipType < SIS_315H)) { - if(resinfo != SIS_RI_1280x1024) { - tempbx += (tempax << 1); - } - } else if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_LCDResInfo != Panel_1400x1050) { - tempbx += (tempax << 1); - } - } + SiS_CalcCRRegisters(SiS_Pr, 0); + SiS_Pr->CCRT1CRTC[16] &= ~0xE0; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - tempbx -= 10; - } else { - if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - tempbx += 40; - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_VGAHDE == 800) tempbx += 10; - } - } - } + for(i = 0; i <= 7; i++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,CRTranslation[i],SiS_Pr->CCRT1CRTC[i]); } - tempax >>= 2; - tempax++; - tempax += tempbx; - push1 = tempax; - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - if(tempbx <= 513) { - if(tempax >= 513) tempbx = 513; - } + for(i = 0x10, j = 8; i <= 0x12; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,CRTranslation[i],SiS_Pr->CCRT1CRTC[j]); } - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0C,temp); /* 0x0C Vertical Retrace Start */ - - tempbx--; - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,temp); - - if(tempbx & 0x0100) tempcx |= 0x0008; - - if(tempbx & 0x0200) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x0B,0x20); + for(i = 0x15, j = 11; i <= 0x16; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,CRTranslation[i],SiS_Pr->CCRT1CRTC[j]); } - tempbx++; - - if(tempbx & 0x0100) tempcx |= 0x0004; - if(tempbx & 0x0200) tempcx |= 0x0080; - if(tempbx & 0x0400) { - if(HwInfo->jChipType >= SIS_661) tempcx |= 0x0800; - else if(SiS_Pr->SiS_VBType & VB_SIS301) tempcx |= 0x0800; - else tempcx |= 0x0C00; + for(i = 0x0a, j = 13; i <= 0x0c; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,CRTranslation[i],SiS_Pr->CCRT1CRTC[j]); } - tempbx = push1; - temp = tempbx & 0x000F; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0D,temp); /* 0x0D vertical Retrace End */ - - if(tempbx & 0x0010) tempcx |= 0x2000; - - temp = tempcx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp); /* 0x0A CR07 */ + temp = SiS_Pr->CCRT1CRTC[16] & 0xE0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,CRTranslation[0x0E],0x1F,temp); - temp = (tempcx & 0xFF00) >> 8; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp); /* 0x17 SR0A */ - - tempax = modeflag; - temp = (tempax & 0xFF00) >> 8; - temp = (temp >> 1) & 0x09; - if(!(SiS_Pr->SiS_VBType & VB_SIS301)) temp |= 0x01; /* Always 8 dotclock */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp); /* 0x16 SR01 */ + temp = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5; + if(modeflag & DoubleScanMode) temp |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,CRTranslation[0x09],0x5F,temp); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,0x00); /* 0x0F CR14 */ + temp = 0; + temp |= (SiS_GetReg(SiS_Pr->SiS_P3c4,0x01) & 0x01); + if(modeflag & HalfDCLK) temp |= 0x08; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp); /* SR01: HalfDCLK[3], 8/9 div dotclock[0] */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,0x00); /* 0x12 CR17 */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,0x00); /* CR14: (text mode: underline location) */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,0x00); /* CR17: n/a */ - temp = 0x00; + temp = 0; if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { - if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) { - temp = 0x80; - } + temp = (SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) << 7; } - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp); /* 0x1A SR0E */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp); /* SR0E, dither[7] */ temp = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp); /* ? */ + +#ifdef SIS_XORG_XF86 +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "%d %d %d %d %d %d %d %d (%d %d %d %d)\n", + SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal, + SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal, + SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd); + + xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", + SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1], + SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3], + SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5], + SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]); + xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", + SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9], + SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11], + SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13], + SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]); + xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]); +#endif +#endif } /* Setup panel link @@ -5637,18 +5451,18 @@ SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex, * 300/LVDS+TV, 300/301B-DH, 315/LVDS+TV, 315/LCDA */ static void -SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex) +SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { - USHORT modeflag,resinfo; - USHORT push2,tempax,tempbx,tempcx,temp; - ULONG tempeax=0,tempebx,tempecx,tempvcfact=0; + unsigned short modeflag, resinfo = 0; + unsigned short push2, tempax, tempbx, tempcx, temp; + unsigned int tempeax = 0, tempebx, tempecx, tempvcfact = 0; BOOLEAN islvds = FALSE, issis = FALSE, chkdclkfirst = FALSE; #ifdef SIS300 - USHORT crt2crtc; + unsigned short crt2crtc = 0; #endif #ifdef SIS315H - USHORT pushcx; + unsigned short pushcx; #endif if(ModeNo <= 0x13) { @@ -5659,15 +5473,11 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, #endif } else if(SiS_Pr->UseCustomMode) { modeflag = SiS_Pr->CModeFlag; - resinfo = 0; -#ifdef SIS300 - crt2crtc = 0; -#endif } else { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; #ifdef SIS300 - crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; #endif } @@ -5681,14 +5491,14 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, issis = TRUE; } - if((HwInfo->jChipType >= SIS_315H) && (islvds) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA))) { + if((SiS_Pr->ChipType >= SIS_315H) && (islvds) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA))) { if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { chkdclkfirst = TRUE; } } #ifdef SIS315H - if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { if(IS_SIS330) { SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10); } else if(IS_SIS740) { @@ -5704,7 +5514,7 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x00); } else if(SiS_Pr->SiS_VBType & VB_SISVB) { SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2D,0x0f); - if(SiS_Pr->SiS_VBType & VB_SIS301C) { + if(SiS_Pr->SiS_VBType & VB_SIS30xC) { if((SiS_Pr->SiS_LCDResInfo == Panel_1024x768) || (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x20); @@ -5720,10 +5530,10 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, tempax = SiS_Pr->SiS_LCDHDES; if(islvds) { if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { - if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) && - (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) { - tempax -= 8; + if(!SiS_Pr->SiS_IF_DEF_FSTN && !SiS_Pr->SiS_IF_DEF_DSTN) { + if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) && + (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) { + tempax -= 8; } } } @@ -5736,13 +5546,14 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, tempbx = SiS_Pr->SiS_HDE; if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - if((SiS_Pr->SiS_LCDResInfo == Panel_640x480_2) || - (SiS_Pr->SiS_LCDResInfo == Panel_640x480_3)) { - tempbx >>= 1; - } if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { tempbx = SiS_Pr->PanelXRes; } + if((SiS_Pr->SiS_LCDResInfo == Panel_320x240_1) || + (SiS_Pr->SiS_LCDResInfo == Panel_320x240_2) || + (SiS_Pr->SiS_LCDResInfo == Panel_320x240_3)) { + tempbx >>= 1; + } } tempax += tempbx; @@ -5767,25 +5578,25 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, temp = (tempcx >> 3) & 0x00FF; if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { if(SiS_Pr->SiS_IF_DEF_TRUMPION) { - if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { - switch(ModeNo) { - case 0x04: - case 0x05: - case 0x0d: temp = 0x56; break; - case 0x10: temp = 0x60; break; - case 0x13: temp = 0x5f; break; - case 0x40: - case 0x41: - case 0x4f: - case 0x43: - case 0x44: - case 0x62: - case 0x56: - case 0x53: - case 0x5d: - case 0x5e: temp = 0x54; break; - } - } + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + switch(ModeNo) { + case 0x04: + case 0x05: + case 0x0d: temp = 0x56; break; + case 0x10: temp = 0x60; break; + case 0x13: temp = 0x5f; break; + case 0x40: + case 0x41: + case 0x4f: + case 0x43: + case 0x44: + case 0x62: + case 0x56: + case 0x53: + case 0x5d: + case 0x5e: temp = 0x54; break; + } + } } } SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,temp); /* BPLHRS */ @@ -5793,12 +5604,12 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { temp += 2; if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { - temp += 8; - if(SiS_Pr->PanelHRE != 999) { - temp = tempcx + SiS_Pr->PanelHRE; + temp += 8; + if(SiS_Pr->PanelHRE != 999) { + temp = tempcx + SiS_Pr->PanelHRE; if(temp >= SiS_Pr->SiS_HT) temp -= SiS_Pr->SiS_HT; temp >>= 3; - } + } } } else { temp += 10; @@ -5806,9 +5617,6 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, temp &= 0x1F; temp |= ((tempcx & 0x07) << 5); -#if 0 - if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20; /* WRONG? BIOS loads cl, not ah */ -#endif SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,temp); /* BPLHRE */ /* Vertical */ @@ -5826,9 +5634,9 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, push2 = tempbx; tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE; - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->PanelYRes; } } @@ -5844,19 +5652,19 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(issis) tempbx++; } else { tempbx += tempcx; - if(HwInfo->jChipType < SIS_315H) tempbx++; + if(SiS_Pr->ChipType < SIS_315H) tempbx++; else if(issis) tempbx++; } - if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; /* BPLVRS */ + if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; temp = tempbx & 0x00FF; if(SiS_Pr->SiS_IF_DEF_TRUMPION) { if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { - if(ModeNo == 0x10) temp = 0xa9; + if(ModeNo == 0x10) temp = 0xa9; } } - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp); /* BPLVRS */ tempcx >>= 3; tempcx++; @@ -5879,13 +5687,13 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } else if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40; if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) temp |= 0x40; tempbx = 0x87; - if((HwInfo->jChipType >= SIS_315H) || - (HwInfo->jChipRevision >= 0x30)) { + if((SiS_Pr->ChipType >= SIS_315H) || + (SiS_Pr->ChipRevision >= 0x30)) { tempbx = 0x07; if((SiS_Pr->SiS_IF_DEF_CH70xx == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x03) temp |= 0x80; } - /* Chrontel 701x operates in 24bit mode (8-8-8, 2x12bit mutliplexed) via VGA2 */ + /* Chrontel 701x operates in 24bit mode (8-8-8, 2x12bit multiplexed) via VGA2 */ if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x10) temp |= 0x80; @@ -5896,59 +5704,58 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,tempbx,temp); - tempbx = push2; /* BPLVDEE */ + tempbx = push2; /* BPLVDEE */ - tempcx = SiS_Pr->SiS_LCDVDES; /* BPLVDES */ + tempcx = SiS_Pr->SiS_LCDVDES; /* BPLVDES */ if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { switch(SiS_Pr->SiS_LCDResInfo) { case Panel_640x480: - tempbx = SiS_Pr->SiS_VGAVDE - 1; - tempcx = SiS_Pr->SiS_VGAVDE; + tempbx = SiS_Pr->SiS_VGAVDE - 1; + tempcx = SiS_Pr->SiS_VGAVDE; break; case Panel_800x600: - if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - if(resinfo == SIS_RI_800x600) tempcx++; - } + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_800x600) tempcx++; + } break; case Panel_1024x600: - if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - if(resinfo == SIS_RI_1024x600) tempcx++; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_1024x600) tempcx++; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { if(resinfo == SIS_RI_800x600) tempcx++; } - } + } break; case Panel_1024x768: - if(HwInfo->jChipType < SIS_315H) { - if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - if(resinfo == SIS_RI_1024x768) tempcx++; + if(SiS_Pr->ChipType < SIS_315H) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_1024x768) tempcx++; } - } + } break; } } temp = ((tempbx >> 8) & 0x07) << 3; - temp = temp | ((tempcx >> 8) & 0x07); + temp |= ((tempcx >> 8) & 0x07); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1D,temp); - /* if(SiS_Pr->SiS_IF_DEF_FSTN) tempbx++; */ SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1C,tempbx); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1B,tempcx); /* Vertical scaling */ - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 /* 300 series */ tempeax = SiS_Pr->SiS_VGAVDE << 6; - temp = (tempeax % (ULONG)SiS_Pr->SiS_VDE); - tempeax = tempeax / (ULONG)SiS_Pr->SiS_VDE; + temp = (tempeax % (unsigned int)SiS_Pr->SiS_VDE); + tempeax = tempeax / (unsigned int)SiS_Pr->SiS_VDE; if(temp) tempeax++; if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) tempeax = 0x3F; - temp = (USHORT)(tempeax & 0x00FF); + temp = (unsigned short)(tempeax & 0x00FF); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp); /* BPLVCFACT */ tempvcfact = temp; #endif /* SIS300 */ @@ -5963,20 +5770,20 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(temp) tempeax++; tempvcfact = tempeax; - temp = (USHORT)(tempeax & 0x00FF); + temp = (unsigned short)(tempeax & 0x00FF); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,temp); - temp = (USHORT)((tempeax & 0x00FF00) >> 8); + temp = (unsigned short)((tempeax & 0x00FF00) >> 8); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,temp); - temp = (USHORT)((tempeax & 0x00030000) >> 16); + temp = (unsigned short)((tempeax & 0x00030000) >> 16); if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,temp); - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) { - temp = (USHORT)(tempeax & 0x00FF); + if(SiS_Pr->SiS_VBType & VB_SISPART4SCALER) { + temp = (unsigned short)(tempeax & 0x00FF); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3c,temp); - temp = (USHORT)((tempeax & 0x00FF00) >> 8); + temp = (unsigned short)((tempeax & 0x00FF00) >> 8); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3b,temp); - temp = (USHORT)(((tempeax & 0x00030000) >> 16) << 6); + temp = (unsigned short)(((tempeax & 0x00030000) >> 16) << 6); SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0x3f,temp); temp = 0; if(SiS_Pr->SiS_VDE != SiS_Pr->SiS_VGAVDE) temp |= 0x08; @@ -5997,29 +5804,29 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, tempecx = 0xFFFF; } else { tempecx = tempebx / SiS_Pr->SiS_HDE; - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { if(tempebx % SiS_Pr->SiS_HDE) tempecx++; } } - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { tempeax = (tempebx / tempecx) - 1; } else { tempeax = ((SiS_Pr->SiS_VGAHT << 16) / tempecx) - 1; } tempecx = (tempecx << 16) | (tempeax & 0xFFFF); - temp = (USHORT)(tempecx & 0x00FF); + temp = (unsigned short)(tempecx & 0x00FF); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1F,temp); - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact; - tempbx = (USHORT)(tempeax & 0xFFFF); + tempbx = (unsigned short)(tempeax & 0xFFFF); } else { tempeax = SiS_Pr->SiS_VGAVDE << 6; tempbx = tempvcfact & 0x3f; if(tempbx == 0) tempbx = 64; tempeax /= tempbx; - tempbx = (USHORT)(tempeax & 0xFFFF); + tempbx = (unsigned short)(tempeax & 0xFFFF); } if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tempbx--; if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) { @@ -6032,24 +5839,24 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_SetReg(SiS_Pr->SiS_Part1Port,0x20,temp); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x21,tempbx); - tempecx >>= 16; /* BPLHCFACT */ + tempecx >>= 16; /* BPLHCFACT */ if(!chkdclkfirst) { if(modeflag & HalfDCLK) tempecx >>= 1; } - temp = (USHORT)((tempecx & 0xFF00) >> 8); + temp = (unsigned short)((tempecx & 0xFF00) >> 8); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x22,temp); - temp = (USHORT)(tempecx & 0x00FF); + temp = (unsigned short)(tempecx & 0x00FF); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp); #ifdef SIS315H - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - if((islvds) || (SiS_Pr->SiS_VBInfo & VB_SIS301LV302LV)) { + if((islvds) || (SiS_Pr->SiS_VBInfo & VB_SISLVDS)) { SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x20); } } else { if(islvds) { - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03); } else { SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x23); @@ -6061,17 +5868,26 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, #ifdef SIS300 if(SiS_Pr->SiS_IF_DEF_TRUMPION) { - int i; - UCHAR TrumpMode13[4] = { 0x01, 0x10, 0x2c, 0x00 }; - UCHAR TrumpMode10_1[4] = { 0x01, 0x10, 0x27, 0x00 }; - UCHAR TrumpMode10_2[4] = { 0x01, 0x16, 0x10, 0x00 }; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned char *trumpdata; + int i, j = crt2crtc; + unsigned char TrumpMode13[4] = { 0x01, 0x10, 0x2c, 0x00 }; + unsigned char TrumpMode10_1[4] = { 0x01, 0x10, 0x27, 0x00 }; + unsigned char TrumpMode10_2[4] = { 0x01, 0x16, 0x10, 0x00 }; + + if(SiS_Pr->SiS_UseROM) { + trumpdata = &ROMAddr[0x8001 + (j * 80)]; + } else { + if(SiS_Pr->SiS_LCDTypeInfo == 0x0e) j += 7; + trumpdata = &SiS300_TrumpionData[j][0]; + } SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xbf); for(i=0; i<5; i++) { - SiS_SetTrumpionBlock(SiS_Pr, &SiS300_TrumpionData[crt2crtc][0]); + SiS_SetTrumpionBlock(SiS_Pr, trumpdata); } if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { - if(ModeNo == 0x13) { + if(ModeNo == 0x13) { for(i=0; i<4; i++) { SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode13[0]); } @@ -6095,67 +5911,66 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_SetReg(SiS_Pr->SiS_Part1Port,0x29,0x5A); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2A,0x4B); SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x07,0x03); - tempax = SiS_Pr->SiS_HDE; /* Blps = lcdhdee(lcdhdes+HDE) + 64 */ - if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || - SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; + tempax = SiS_Pr->SiS_HDE; /* Blps = lcdhdee(lcdhdes+HDE) + 64 */ + if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_2 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_3) tempax >>= 1; tempax += 64; - temp = tempax & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x38,temp); - temp = ((tempax & 0xFF00) >> 8) << 3; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x38,tempax & 0xff); + temp = (tempax >> 8) << 3; SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,~0x078,temp); - tempax += 32; /* Blpe=lBlps+32 */ - temp = tempax & 0x00FF; - if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x39,temp); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3A,0x00); /* Bflml=0 */ - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x007,0x00); + tempax += 32; /* Blpe = lBlps+32 */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x39,tempax & 0xff); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3A,0x00); /* Bflml = 0 */ + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x3C,~0x007); tempax = SiS_Pr->SiS_VDE; - if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || - SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; + if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_2 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_3) tempax >>= 1; tempax >>= 1; - temp = tempax & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3B,temp); - temp = ((tempax & 0xFF00) >> 8) << 3; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3B,tempax & 0xff); + temp = (tempax >> 8) << 3; SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x038,temp); tempeax = SiS_Pr->SiS_HDE; - if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || - SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempeax >>= 1; - tempeax <<= 2; /* BDxFIFOSTOP = (HDE*4)/128 */ - tempebx = 128; - temp = (USHORT)(tempeax % tempebx); - tempeax = tempeax / tempebx; + if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_2 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_3) tempeax >>= 1; + tempeax <<= 2; /* BDxFIFOSTOP = (HDE*4)/128 */ + temp = tempeax & 0x7f; + tempeax >>= 7; if(temp) tempeax++; - temp = (USHORT)(tempeax & 0x003F); - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x45,~0x0FF,temp); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3F,0x00); /* BDxWadrst0 */ + temp = tempeax & 0x3f; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x45,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3F,0x00); /* BDxWadrst0 */ SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3E,0x00); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3D,0x10); - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x040,0x00); + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x3C,~0x040); tempax = SiS_Pr->SiS_HDE; - if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || - SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; - tempax >>= 4; /* BDxWadroff = HDE*4/8/8 */ + if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_2 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_3) tempax >>= 1; + tempax >>= 4; /* BDxWadroff = HDE*4/8/8 */ pushcx = tempax; temp = tempax & 0x00FF; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x43,temp); temp = ((tempax & 0xFF00) >> 8) << 3; SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x0F8,temp); - tempax = SiS_Pr->SiS_VDE; /* BDxWadrst1 = BDxWadrst0 + BDxWadroff * VDE */ - if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || - SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; - tempeax = (tempax * pushcx); - tempebx = 0x00100000 + tempeax; - temp = (USHORT)tempebx & 0x000000FF; + tempax = SiS_Pr->SiS_VDE; /* BDxWadrst1 = BDxWadrst0 + BDxWadroff * VDE */ + if(SiS_Pr->SiS_LCDResInfo == Panel_320x240_1 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_2 || + SiS_Pr->SiS_LCDResInfo == Panel_320x240_3) tempax >>= 1; + tempeax = tempax * pushcx; + temp = tempeax & 0xFF; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x42,temp); - temp = (USHORT)((tempebx & 0x0000FF00) >> 8); + temp = (tempeax & 0xFF00) >> 8; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x41,temp); - temp = (USHORT)((tempebx & 0x00FF0000) >> 16); + temp = ((tempeax & 0xFF0000) >> 16) | 0x10; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x40,temp); - temp = (USHORT)(((tempebx & 0x01000000) >> 24) << 7); + temp = ((tempeax & 0x01000000) >> 24) << 7; SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x080,temp); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2F,0x03); @@ -6192,20 +6007,20 @@ SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /* Set Part 1 */ static void -SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex) +SiS_SetGroup1(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { #if defined(SIS300) || defined(SIS315H) - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; #endif - USHORT temp=0, tempax=0, tempbx=0, tempcx=0, bridgeadd=0; - USHORT pushbx=0, CRT1Index=0, modeflag, resinfo=0; + unsigned short temp=0, tempax=0, tempbx=0, tempcx=0, bridgeadd=0; + unsigned short pushbx=0, CRT1Index=0, modeflag, resinfo=0; #ifdef SIS315H - USHORT tempbl=0; + unsigned short tempbl=0; #endif if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); return; } @@ -6214,47 +6029,47 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } else if(SiS_Pr->UseCustomMode) { modeflag = SiS_Pr->CModeFlag; } else { - CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index = SiS_GetRefCRT1CRTC(SiS_Pr, RefreshRateTableIndex, SiS_Pr->SiS_UseWideCRT2); resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; } - SiS_SetCRT2Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + SiS_SetCRT2Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); - if( ! ((HwInfo->jChipType >= SIS_315H) && + if( ! ((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) { - if(HwInfo->jChipType < SIS_315H ) { + if(SiS_Pr->ChipType < SIS_315H ) { #ifdef SIS300 - SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo, HwInfo); + SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo); #endif } else { #ifdef SIS315H - SiS_SetCRT2FIFO_310(SiS_Pr, HwInfo); + SiS_SetCRT2FIFO_310(SiS_Pr); #endif } /* 1. Horizontal setup */ - if(HwInfo->jChipType < SIS_315H ) { + if(SiS_Pr->ChipType < SIS_315H ) { #ifdef SIS300 /* ------------- 300 series --------------*/ - temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */ + temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */ - temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp); /* CRT2 Horizontal Total Overflow [7:4] */ + temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp); /* CRT2 Horizontal Total Overflow [7:4] */ - temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp); /* CRT2 Horizontal Display Enable End */ + temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp); /* CRT2 Horizontal Display Enable End */ pushbx = SiS_Pr->SiS_VGAHDE + 12; /* bx BTVGA2HRS 0x0B,0x0C */ - tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2; - tempbx = pushbx + tempcx; - tempcx <<= 1; - tempcx += tempbx; + tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2; + tempbx = pushbx + tempcx; + tempcx <<= 1; + tempcx += tempbx; bridgeadd = 12; @@ -6301,7 +6116,7 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, bridgeadd = 16; if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->ChipType >= SIS_661) { if((SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) || (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { if(resinfo == SIS_RI_1280x1024) { @@ -6319,7 +6134,7 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->UseCustomMode) { + if(SiS_Pr->UseCustomMode) { tempbx = SiS_Pr->CHSyncStart + bridgeadd; tempcx = SiS_Pr->CHSyncEnd + bridgeadd; tempax = SiS_Pr->SiS_VGAHT; @@ -6341,22 +6156,22 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, cr5 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5]; cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15]; } - tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 3) << 3; /* (VGAHRS-3)*8 */ - tempcx = (((cr5 & 0x1f) | ((cr15 & 0x04) << (5-2))) - 3) << 3; /* (VGAHRE-3)*8 */ + tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 3) << 3; /* (VGAHRS-3)*8 */ + tempcx = (((cr5 & 0x1f) | ((cr15 & 0x04) << (5-2))) - 3) << 3; /* (VGAHRE-3)*8 */ tempcx &= 0x00FF; tempcx |= (tempbx & 0xFF00); - tempbx += bridgeadd; - tempcx += bridgeadd; + tempbx += bridgeadd; + tempcx += bridgeadd; tempax = SiS_Pr->SiS_VGAHT; if(modeflag & HalfDCLK) tempax >>= 1; tempax--; if(tempcx > tempax) tempcx = tempax; - } + } - if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { - tempbx = 1040; - tempcx = 1044; /* HWCursor bug! */ - } + if(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSet525p1024)) { + tempbx = 1040; + tempcx = 1044; /* HWCursor bug! */ + } } @@ -6372,18 +6187,18 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, tempcx = SiS_Pr->SiS_VGAVT - 1; temp = tempcx & 0x00FF; - if(HwInfo->jChipType < SIS_661) { + if(SiS_Pr->ChipType < SIS_661) { if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) { temp--; } - } + } } else { - temp--; - } - } else if(HwInfo->jChipType >= SIS_315H) { + temp--; + } + } else if(SiS_Pr->ChipType >= SIS_315H) { temp--; } } @@ -6395,9 +6210,9 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, temp = ((tempbx >> 5) & 0x38) | ((tempcx >> 8) & 0x07); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,temp); /* Overflow */ - if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) { - tempbx++; - tempax = tempbx; + if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) { + tempbx++; + tempax = tempbx; tempcx++; tempcx -= tempax; tempcx >>= 2; @@ -6407,8 +6222,8 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, tempcx += tempbx; tempcx++; } else { - tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1; /* BTVGA2VRS 0x10,0x11 */ - tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1; /* BTVGA2VRE 0x11 */ + tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1; /* BTVGA2VRS 0x10,0x11 */ + tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1; /* BTVGA2VRE 0x11 */ } if(SiS_Pr->SiS_VBType & VB_SISVB) { @@ -6416,7 +6231,7 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, tempbx = SiS_Pr->CVSyncStart; tempcx = SiS_Pr->CVSyncEnd; } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { unsigned char cr8, cr7, cr13; if(SiS_Pr->UseCustomMode) { cr8 = SiS_Pr->CCRT1CRTC[8]; @@ -6429,11 +6244,11 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, cr13 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9]; } - tempbx = cr8; - if(cr7 & 0x04) tempbx |= 0x0100; - if(cr7 & 0x80) tempbx |= 0x0200; - if(cr13 & 0x08) tempbx |= 0x0400; - } + tempbx = cr8; + if(cr7 & 0x04) tempbx |= 0x0100; + if(cr7 & 0x80) tempbx |= 0x0200; + if(cr13 & 0x08) tempbx |= 0x0400; + } } SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,tempbx); /* CRT2 Vertical Retrace Start */ @@ -6442,13 +6257,13 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /* 3. Panel delay compensation */ - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { #ifdef SIS300 /* ---------- 300 series -------------- */ if(SiS_Pr->SiS_VBType & VB_SISVB) { temp = 0x20; - if(HwInfo->jChipType == SIS_300) { + if(SiS_Pr->ChipType == SIS_300) { temp = 0x10; if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) temp = 0x2c; if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20; @@ -6460,24 +6275,23 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) temp = 0x2c; if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x08; if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) temp = 0x2c; - else temp = 0x20; - } + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) temp = 0x2c; + else temp = 0x20; + } if(SiS_Pr->SiS_UseROM) { if(ROMAddr[0x220] & 0x80) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) - temp = ROMAddr[0x221]; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) + temp = ROMAddr[0x221]; else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) temp = ROMAddr[0x222]; else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = ROMAddr[0x223]; else temp = ROMAddr[0x224]; - temp &= 0x3c; } } if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC & 0x3c; + if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC; } } else { @@ -6487,15 +6301,17 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } if(SiS_Pr->SiS_UseROM) { if(ROMAddr[0x220] & 0x80) { - temp = ROMAddr[0x220] & 0x3c; + temp = ROMAddr[0x220]; } } if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC & 0x3c; + if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC; } - } + } - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */ + temp &= 0x3c; + + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */ #endif /* SIS300 */ @@ -6503,16 +6319,16 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, #ifdef SIS315H /* --------------- 315/330 series ---------------*/ - if(HwInfo->jChipType < SIS_661) { + if(SiS_Pr->ChipType < SIS_661) { if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(HwInfo->jChipType == SIS_740) temp = 0x03; - else temp = 0x00; + if(SiS_Pr->ChipType == SIS_740) temp = 0x03; + else temp = 0x00; if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x0a; tempbl = 0xF0; - if(HwInfo->jChipType == SIS_650) { + if(SiS_Pr->ChipType == SIS_650) { if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F; } @@ -6531,10 +6347,10 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } /* < 661 */ - tempax = 0; - if(modeflag & DoubleScanMode) tempax |= 0x80; - if(modeflag & HalfDCLK) tempax |= 0x40; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax); + tempax = 0; + if(modeflag & DoubleScanMode) tempax |= 0x80; + if(modeflag & HalfDCLK) tempax |= 0x40; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax); #endif /* SIS315H */ @@ -6544,21 +6360,21 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(SiS_Pr->SiS_VBType & VB_SISVB) { if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { - /* For 301BDH with LCD, we set up the Panel Link */ - SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + /* For 301BDH with LCD, we set up the Panel Link */ + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - SiS_SetGroup1_301(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + SiS_SetGroup1_301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } } else { - if(HwInfo->jChipType < SIS_315H) { - SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + if(SiS_Pr->ChipType < SIS_315H) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } else { if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, HwInfo,RefreshRateTableIndex); - } + if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex,RefreshRateTableIndex); + } } else { - SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, HwInfo,RefreshRateTableIndex); + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex,RefreshRateTableIndex); } } } @@ -6569,11 +6385,11 @@ SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ #ifdef SIS315H -static UCHAR * -SiS_GetGroup2CLVXPtr(SiS_Private *SiS_Pr, int tabletype, PSIS_HW_INFO HwInfo) +static unsigned char * +SiS_GetGroup2CLVXPtr(struct SiS_Private *SiS_Pr, int tabletype) { - const UCHAR *tableptr = NULL; - USHORT a, b, p = 0; + const unsigned char *tableptr = NULL; + unsigned short a, b, p = 0; a = SiS_Pr->SiS_VGAHDE; b = SiS_Pr->SiS_HDE; @@ -6606,25 +6422,25 @@ SiS_GetGroup2CLVXPtr(SiS_Private *SiS_Pr, int tabletype, PSIS_HW_INFO HwInfo) if((tableptr[p] | tableptr[p+1] << 8) == 0xffff) p -= 0x42; } p += 2; - return((UCHAR *)&tableptr[p]); + return ((unsigned char *)&tableptr[p]); } static void -SiS_SetGroup2_C_ELV(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +SiS_SetGroup2_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { - UCHAR *tableptr; + unsigned char *tableptr; + unsigned char temp; int i, j; - UCHAR temp; - if(!(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV))) return; + if(!(SiS_Pr->SiS_VBType & VB_SISTAP4SCALER)) return; - tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 0, HwInfo); + tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 0); for(i = 0x80, j = 0; i <= 0xbf; i++, j++) { SiS_SetReg(SiS_Pr->SiS_Part2Port, i, tableptr[j]); } if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 1, HwInfo); + tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 1); for(i = 0xc0, j = 0; i <= 0xff; i++, j++) { SiS_SetReg(SiS_Pr->SiS_Part2Port, i, tableptr[j]); } @@ -6635,12 +6451,12 @@ SiS_SetGroup2_C_ELV(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, } static BOOLEAN -SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, - USHORT RefreshRateTableIndex,USHORT *CRT2Index, - USHORT *ResIndex,PSIS_HW_INFO HwInfo) +SiS_GetCRT2Part2Ptr(struct SiS_Private *SiS_Pr,unsigned short ModeNo,unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex,unsigned short *CRT2Index, + unsigned short *ResIndex) { - if(HwInfo->jChipType < SIS_315H) return FALSE; + if(SiS_Pr->ChipType < SIS_315H) return FALSE; if(ModeNo <= 0x13) (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; @@ -6661,82 +6477,79 @@ SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, if(SiS_Pr->SiS_SetFlag & LCDVESATiming) (*CRT2Index) = 206; } } - return(((*CRT2Index) != 0)); + return (((*CRT2Index) != 0)); } #endif #ifdef SIS300 static void -SiS_Group2LCDSpecial(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT crt2crtc) +SiS_Group2LCDSpecial(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short crt2crtc) { - USHORT tempcx; - const UCHAR atable[] = { + unsigned short tempcx; + static const unsigned char atable[] = { 0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02, 0xab,0x87,0xab,0x9e,0xe7,0x02,0x02 }; if(!SiS_Pr->UseCustomMode) { - if( ( ( (HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730) ) && - (HwInfo->jChipRevision > 2) ) && - (SiS_Pr->SiS_LCDResInfo == Panel_1024x768) && - (!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) && - (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) { - if(ModeNo == 0x13) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xB9); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0xCC); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xA6); - } else { - if((crt2crtc & 0x3F) == 4) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x2B); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x13); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xE5); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0x08); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xE2); - } - } + if( ( ( (SiS_Pr->ChipType == SIS_630) || + (SiS_Pr->ChipType == SIS_730) ) && + (SiS_Pr->ChipRevision > 2) ) && + (SiS_Pr->SiS_LCDResInfo == Panel_1024x768) && + (!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) && + (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) { + if(ModeNo == 0x13) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xB9); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0xCC); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xA6); + } else if((crt2crtc & 0x3F) == 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x2B); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x13); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xE5); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0x08); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xE2); + } } - if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) { - crt2crtc &= 0x1f; - tempcx = 0; - if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - tempcx += 7; - } - } - tempcx += crt2crtc; - if(crt2crtc >= 4) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xff); - } + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) { + crt2crtc &= 0x1f; + tempcx = 0; + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + tempcx += 7; + } + } + tempcx += crt2crtc; + if(crt2crtc >= 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xff); + } - if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - if(crt2crtc == 4) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x28); - } - } - } - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x18); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]); - } + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(crt2crtc == 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x28); + } + } + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x18); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]); + } } } } /* For ECS A907. Highly preliminary. */ static void -SiS_Set300Part2Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeIdIndex, USHORT RefreshRateTableIndex, - USHORT ModeNo) +SiS_Set300Part2Regs(struct SiS_Private *SiS_Pr, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, + unsigned short ModeNo) { - USHORT crt2crtc, resindex; - int i,j; - const SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL; + const struct SiS_Part2PortTbl *CRT2Part2Ptr = NULL; + unsigned short crt2crtc, resindex; + int i, j; - if(HwInfo->jChipType != SIS_300) return; - if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return; + if(SiS_Pr->ChipType != SIS_300) return; + if(!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) return; if(SiS_Pr->UseCustomMode) return; if(ModeNo <= 0x13) { @@ -6758,13 +6571,13 @@ SiS_Set300Part2Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x02,0x80,(CRT2Part2Ptr+resindex)->CR[1]); for(i = 2, j = 0x04; j <= 0x06; i++, j++ ) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); } for(j = 0x1c; j <= 0x1d; i++, j++ ) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); } for(j = 0x1f; j <= 0x21; i++, j++ ) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); + SiS_SetReg(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]); } SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]); @@ -6772,15 +6585,15 @@ SiS_Set300Part2Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, #endif static void -SiS_SetTVSpecial(SiS_Private *SiS_Pr, USHORT ModeNo) +SiS_SetTVSpecial(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { - if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return; + if(!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) return; if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision)) return; if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) return; if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { - const UCHAR specialtv[] = { + const unsigned char specialtv[] = { 0xa7,0x07,0xf2,0x6e,0x17,0x8b,0x73,0x53, 0x13,0x40,0x34,0xf4,0x63,0xbb,0xcc,0x7a, 0x58,0xe4,0x73,0xda,0x13 @@ -6813,16 +6626,16 @@ SiS_SetTVSpecial(SiS_Private *SiS_Pr, USHORT ModeNo) } static void -SiS_SetGroup2_Tail(SiS_Private *SiS_Pr, USHORT ModeNo) +SiS_SetGroup2_Tail(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { - USHORT temp; + unsigned short temp; if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { if(SiS_Pr->SiS_VGAVDE == 525) { temp = 0xc3; if(SiS_Pr->SiS_ModeType <= ModeVGA) { temp++; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) temp += 2; } SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xb3); @@ -6830,7 +6643,7 @@ SiS_SetGroup2_Tail(SiS_Private *SiS_Pr, USHORT ModeNo) temp = 0x4d; if(SiS_Pr->SiS_ModeType <= ModeVGA) { temp++; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) temp++; } SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); } @@ -6838,7 +6651,7 @@ SiS_SetGroup2_Tail(SiS_Private *SiS_Pr, USHORT ModeNo) if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) { - if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + if(SiS_Pr->SiS_VBType & VB_SIS30xB) { SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x1a,0x03); /* Not always for LV, see SetGrp2 */ } @@ -6872,17 +6685,17 @@ SiS_SetGroup2_Tail(SiS_Private *SiS_Pr, USHORT ModeNo) } static void -SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT RefreshRateTableIndex, - PSIS_HW_INFO HwInfo) -{ - USHORT i, j, tempax, tempbx, tempcx, tempch, tempcl, temp; - USHORT push2, modeflag, crt2crtc, bridgeoffset; - ULONG longtemp; - const UCHAR *PhasePoint; - const UCHAR *TimingPoint; +SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short i, j, tempax, tempbx, tempcx, tempch, tempcl, temp; + unsigned short push2, modeflag, crt2crtc, bridgeoffset; + unsigned int longtemp, PhaseIndex; + BOOLEAN newtvphase; + const unsigned char *TimingPoint; #ifdef SIS315H - USHORT resindex, CRT2Index; - const SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL; + unsigned short resindex, CRT2Index; + const struct SiS_Part2PortTbl *CRT2Part2Ptr = NULL; if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; #endif @@ -6908,9 +6721,16 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr SiS_SetReg(SiS_Pr->SiS_Part2Port,0x00,temp); - PhasePoint = SiS_Pr->SiS_PALPhase; + PhaseIndex = 0x01; /* SiS_PALPhase */ TimingPoint = SiS_Pr->SiS_PALTiming; + newtvphase = FALSE; + if( (SiS_Pr->SiS_VBType & VB_SIS30xBLV) && + ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { + newtvphase = TRUE; + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { TimingPoint = SiS_Pr->SiS_HiTVExtTiming; @@ -6918,82 +6738,54 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr TimingPoint = SiS_Pr->SiS_HiTVSt2Timing; if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { TimingPoint = SiS_Pr->SiS_HiTVSt1Timing; -#if 0 - if(!(modeflag & Charx8Dot)) TimingPoint = SiS_Pr->SiS_HiTVTextTiming; -#endif } } } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) TimingPoint = &SiS_YPbPrTable[2][0]; - else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) TimingPoint = &SiS_YPbPrTable[1][0]; - else TimingPoint = &SiS_YPbPrTable[0][0]; + i = 0; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) i = 2; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) i = 1; - PhasePoint = SiS_Pr->SiS_NTSCPhase; + TimingPoint = &SiS_YPbPrTable[i][0]; + + PhaseIndex = 0x00; /* SiS_NTSCPhase */ } else if(SiS_Pr->SiS_TVMode & TVSetPAL) { - if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && - ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || - (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { - PhasePoint = SiS_Pr->SiS_PALPhase2; - } + if(newtvphase) PhaseIndex = 0x09; /* SiS_PALPhase2 */ } else { TimingPoint = SiS_Pr->SiS_NTSCTiming; - PhasePoint = SiS_Pr->SiS_NTSCPhase; - if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { - PhasePoint = SiS_Pr->SiS_PALPhase; - } - - if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && - ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || - (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { - PhasePoint = SiS_Pr->SiS_NTSCPhase2; - if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { - PhasePoint = SiS_Pr->SiS_PALPhase2; - } - } - - } + PhaseIndex = (SiS_Pr->SiS_TVMode & TVSetNTSCJ) ? 0x01 : 0x00; /* SiS_PALPhase : SiS_NTSCPhase */ + if(newtvphase) PhaseIndex += 8; /* SiS_PALPhase2 : SiS_NTSCPhase2 */ - if(SiS_Pr->SiS_TVMode & TVSetPALM) { - PhasePoint = SiS_Pr->SiS_PALMPhase; - if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && - ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || - (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { - PhasePoint = SiS_Pr->SiS_PALMPhase2; - } } - if(SiS_Pr->SiS_TVMode & TVSetPALN) { - PhasePoint = SiS_Pr->SiS_PALNPhase; - if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && - ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || - (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { - PhasePoint = SiS_Pr->SiS_PALNPhase2; - } + if(SiS_Pr->SiS_TVMode & (TVSetPALM | TVSetPALN)) { + PhaseIndex = (SiS_Pr->SiS_TVMode & TVSetPALM) ? 0x02 : 0x03; /* SiS_PALMPhase : SiS_PALNPhase */ + if(newtvphase) PhaseIndex += 8; /* SiS_PALMPhase2 : SiS_PALNPhase2 */ } if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { - PhasePoint = SiS_Pr->SiS_SpecialPhase; if(SiS_Pr->SiS_TVMode & TVSetPALM) { - PhasePoint = SiS_Pr->SiS_SpecialPhaseM; + PhaseIndex = 0x05; /* SiS_SpecialPhaseM */ } else if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { - PhasePoint = SiS_Pr->SiS_SpecialPhaseJ; + PhaseIndex = 0x11; /* SiS_SpecialPhaseJ */ + } else { + PhaseIndex = 0x10; /* SiS_SpecialPhase */ } } - for(i=0x31, j=0; i<=0x34; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,i,PhasePoint[j]); + for(i = 0x31, j = 0; i <= 0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS_TVPhase[(PhaseIndex * 4) + j]); } - for(i=0x01, j=0; i<=0x2D; i++, j++) { + for(i = 0x01, j = 0; i <= 0x2D; i++, j++) { SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); } - for(i=0x39; i<=0x45; i++, j++) { + for(i = 0x39; i <= 0x45; i++, j++) { SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); } @@ -7010,28 +6802,32 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr SiS_SetReg(SiS_Pr->SiS_Part2Port,0x37,SiS_Pr->SiS_RY3COE); SiS_SetReg(SiS_Pr->SiS_Part2Port,0x38,SiS_Pr->SiS_RY4COE); - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempax = 950; - else if(SiS_Pr->SiS_TVMode & TVSetPAL) tempax = 520; - else tempax = 440; /* NTSC, YPbPr 525, 750 */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempax = 950; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempax = 680; + else if(SiS_Pr->SiS_TVMode & TVSetPAL) tempax = 520; + else tempax = 440; /* NTSC, YPbPr 525 */ - if( ( (!(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision)) && (SiS_Pr->SiS_VDE <= tempax) ) || + if( ((SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) && (SiS_Pr->SiS_VDE <= tempax)) || ( (SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) && ((SiS_Pr->SiS_VGAHDE == 1024) || (SiS_Pr->SiS_VDE <= tempax)) ) ) { tempax -= SiS_Pr->SiS_VDE; - tempax >>= 2; + tempax >>= 1; + if(!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p))) { + tempax >>= 1; + } tempax &= 0x00ff; - temp = tempax + (USHORT)TimingPoint[0]; + temp = tempax + (unsigned short)TimingPoint[0]; SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp); - temp = tempax + (USHORT)TimingPoint[1]; + temp = tempax + (unsigned short)TimingPoint[1]; SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp); if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) && (SiS_Pr->SiS_VGAHDE >= 1024)) { if(SiS_Pr->SiS_TVMode & TVSetPAL) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b); /* 19 */ - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54); /* 52 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54); } else { SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x17); SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1d); @@ -7041,14 +6837,14 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr } tempcx = SiS_Pr->SiS_HT; - if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1; + if(SiS_IsDualLink(SiS_Pr)) tempcx >>= 1; tempcx--; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) tempcx--; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) tempcx--; SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1B,tempcx); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0xF0,((tempcx >> 8) & 0x0f)); tempcx = SiS_Pr->SiS_HT >> 1; - if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1; + if(SiS_IsDualLink(SiS_Pr)) tempcx >>= 1; tempcx += 7; if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4; SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,((tempcx << 4) & 0xf0)); @@ -7075,7 +6871,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2A,0x0F,((tempcx << 4) & 0xf0)); tempcx = SiS_Pr->SiS_HT >> 1; - if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1; + if(SiS_IsDualLink(SiS_Pr)) tempcx >>= 1; j += 2; tempcx -= (TimingPoint[j] | ((TimingPoint[j+1]) << 8)); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2D,0x0F,((tempcx << 4) & 0xf0)); @@ -7094,7 +6890,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr } else if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p|TVSetYPbPr750p))) ) { tempbx >>= 1; - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { if((ModeNo <= 0x13) && (crt2crtc == 1)) tempbx++; } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { @@ -7123,23 +6919,11 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr } SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,temp); - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_Pr->SiS_VBType & VB_SISPART4OVERFLOW) { SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,0xdf,((tempbx & 0x0400) >> 5)); } -#if 0 - /* TEST qqqq */ - if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - for(i=0x01, j=0; i<=0x2D; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); - } - for(i=0x39; i<=0x45; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); - } - } -#endif - - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { tempbx = SiS_Pr->SiS_VDE; if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p))) ) { @@ -7150,7 +6934,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr SiS_SetReg(SiS_Pr->SiS_Part2Port,0x46,temp); SiS_SetReg(SiS_Pr->SiS_Part2Port,0x47,tempbx); - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_Pr->SiS_VBType & VB_SISPART4OVERFLOW) { SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,0xbf,((tempbx & 0x0400) >> 4)); } } @@ -7165,14 +6949,17 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr tempch = tempcl = 0x01; if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - if(SiS_Pr->SiS_VGAHDE >= 1024) { - if((!(modeflag & HalfDCLK)) || (HwInfo->jChipType < SIS_315H)) { - tempch = 0x19; + if(SiS_Pr->SiS_VGAHDE >= 960) { + if((!(modeflag & HalfDCLK)) || (SiS_Pr->ChipType < SIS_315H)) { tempcl = 0x20; - if(SiS_Pr->SiS_VGAHDE >= 1280) { - tempch = 0x14; + if(SiS_Pr->SiS_VGAHDE >= 1280) { + tempch = 20; tempbx &= ~0x20; - } + } else if(SiS_Pr->SiS_VGAHDE >= 1024) { + tempch = 25; + } else { + tempch = 25; /* OK */ + } } } } @@ -7180,7 +6967,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr if(!(tempbx & 0x20)) { if(modeflag & HalfDCLK) tempcl <<= 1; longtemp = ((SiS_Pr->SiS_VGAHDE * tempch) / tempcl) << 13; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) longtemp <<= 3; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) longtemp <<= 3; tempax = longtemp / SiS_Pr->SiS_HDE; if(longtemp % SiS_Pr->SiS_HDE) tempax++; tempbx |= ((tempax >> 8) & 0x1F); @@ -7190,7 +6977,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr SiS_SetReg(SiS_Pr->SiS_Part2Port,0x44,tempax); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x45,0xC0,tempbx); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { tempcx &= 0x07; if(tempbx & 0x20) tempcx = 0; @@ -7219,7 +7006,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr SiS_SetTVSpecial(SiS_Pr, ModeNo); - if(SiS_Pr->SiS_VBType & VB_SIS301C) { + if(SiS_Pr->SiS_VBType & VB_SIS30xCLV) { temp = 0; if(SiS_Pr->SiS_TVMode & TVSetPALM) temp = 8; SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xf7,temp); @@ -7246,7 +7033,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr /* From here: Part2 LCD setup */ tempbx = SiS_Pr->SiS_HDE; - if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + if(SiS_IsDualLink(SiS_Pr)) tempbx >>= 1; tempbx--; /* RHACTE = HDE - 1 */ SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2C,tempbx); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2B,0x0F,((tempbx >> 4) & 0xf0)); @@ -7256,10 +7043,8 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr if(SiS_Pr->SiS_ModeType == ModeEGA) { if(SiS_Pr->SiS_VGAHDE >= 1024) { temp = 0x02; - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { - temp = 0x01; - } + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + temp = 0x01; } } } @@ -7289,11 +7074,11 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr #ifdef SIS315H if(SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, - &CRT2Index, &resindex, HwInfo)) { + &CRT2Index, &resindex)) { switch(CRT2Index) { + case 206: CRT2Part2Ptr = SiS310_CRT2Part2_Asus1024x768_3; break; + default: case 200: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1; break; - case 206: CRT2Part2Ptr = SiS310_CRT2Part2_Asus1024x768_3; break; - default: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3; break; } SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]); @@ -7312,7 +7097,6 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr SiS_SetGroup2_Tail(SiS_Pr, ModeNo); - } else { #endif @@ -7349,8 +7133,10 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr /* Non-expanding: lcdvdes = tempcx = VT-1; lcdvdee = tempbx = VDE-1 */ +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "lcdvdes 0x%x lcdvdee 0x%x\n", tempcx, tempbx); +#endif #endif SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempcx); /* lcdvdes */ @@ -7401,8 +7187,10 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr tempbx = SiS_Pr->CVSyncStart; } +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "lcdvrs 0x%x\n", tempbx); +#endif #endif SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx); /* lcdvrs */ @@ -7416,26 +7204,30 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr temp |= (SiS_Pr->CVSyncEnd & 0x0f); } +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "lcdvre[3:0] 0x%x\n", (temp & 0x0f)); +#endif #endif SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp); #ifdef SIS300 - SiS_Group2LCDSpecial(SiS_Pr, HwInfo, ModeNo, crt2crtc); + SiS_Group2LCDSpecial(SiS_Pr, ModeNo, crt2crtc); #endif bridgeoffset = 7; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) bridgeoffset += 2; - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) bridgeoffset++; - if(SiS_IsDualLink(SiS_Pr, HwInfo)) bridgeoffset++; + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) bridgeoffset += 2; + if(SiS_Pr->SiS_VBType & VB_SIS30xCLV) bridgeoffset += 2; /* OK for Averatec 1280x800 (301C) */ + if(SiS_IsDualLink(SiS_Pr)) bridgeoffset++; + else if(SiS_Pr->SiS_VBType & VB_SIS302LV) bridgeoffset++; /* OK for Asus A4L 1280x800 */ + /* Higher bridgeoffset shifts to the LEFT */ temp = 0; if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) { - temp = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2); - if(SiS_IsDualLink(SiS_Pr, HwInfo)) temp >>= 1; + temp = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2); + if(SiS_IsDualLink(SiS_Pr)) temp >>= 1; } } temp += bridgeoffset; @@ -7450,14 +7242,16 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr tempbx = SiS_Pr->PanelXRes - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2); } } - if(SiS_IsDualLink(SiS_Pr, HwInfo)) { + if(SiS_IsDualLink(SiS_Pr)) { tempcx >>= 1; tempbx >>= 1; tempax >>= 1; } +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "lcdhdee 0x%x\n", tempbx); +#endif #endif tempbx += bridgeoffset; @@ -7480,12 +7274,15 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr if(SiS_Pr->UseCustomMode) { tempbx = SiS_Pr->CHSyncStart; - if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + if(modeflag & HalfDCLK) tempbx <<= 1; + if(SiS_IsDualLink(SiS_Pr)) tempbx >>= 1; tempbx += bridgeoffset; } +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "lcdhrs 0x%x\n", tempbx); +#endif #endif SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,tempbx); /* lcdhrs */ @@ -7501,12 +7298,15 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr if(SiS_Pr->UseCustomMode) { tempbx = SiS_Pr->CHSyncEnd; - if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + if(modeflag & HalfDCLK) tempbx <<= 1; + if(SiS_IsDualLink(SiS_Pr)) tempbx >>= 1; tempbx += bridgeoffset; } +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "lcdhre 0x%x\n", tempbx); +#endif #endif SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempbx); /* lcdhre */ @@ -7514,7 +7314,7 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr SiS_SetGroup2_Tail(SiS_Pr, ModeNo); #ifdef SIS300 - SiS_Set300Part2Regs(SiS_Pr, HwInfo, ModeIdIndex, RefreshRateTableIndex, ModeNo); + SiS_Set300Part2Regs(SiS_Pr, ModeIdIndex, RefreshRateTableIndex, ModeNo); #endif #ifdef SIS315H } /* CRT2-LCD from table */ @@ -7526,11 +7326,10 @@ SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT Refr /*********************************************/ static void -SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo) +SiS_SetGroup3(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - USHORT i; - const UCHAR *tempdi; + unsigned short i; + const unsigned char *tempdi; if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; @@ -7570,7 +7369,7 @@ SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, for(i=0; i<=0x3E; i++) { SiS_SetReg(SiS_Pr->SiS_Part3Port,i,tempdi[i]); } - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) { + if(SiS_Pr->SiS_VBType & VB_SIS30xCLV) { if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { SiS_SetReg(SiS_Pr->SiS_Part3Port,0x28,0x3f); } @@ -7587,35 +7386,43 @@ SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ #ifdef SIS315H +#if 0 static void -SiS_ShiftXPos(SiS_Private *SiS_Pr, int shift) +SiS_ShiftXPos(struct SiS_Private *SiS_Pr, int shift) { - USHORT temp, temp1, temp2; + unsigned short temp, temp1, temp2; temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x1f); temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x20); - temp = (USHORT)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift); + temp = (unsigned short)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift); SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1f,temp); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0f,((temp >> 4) & 0xf0)); temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x2b) & 0x0f; - temp = (USHORT)((int)(temp) + shift); + temp = (unsigned short)((int)(temp) + shift); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2b,0xf0,(temp & 0x0f)); temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x43); temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x42); - temp = (USHORT)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift); + temp = (unsigned short)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift); SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,temp); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x42,0x0f,((temp >> 4) & 0xf0)); } +#endif static void -SiS_SetGroup4_C_ELV(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo, USHORT ModeIdIndex) +SiS_SetGroup4_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - USHORT temp, temp1, resinfo = 0; + unsigned short temp, temp1, resinfo = 0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; - if(!(SiS_Pr->SiS_VBType & VB_SIS301C)) return; + if(!(SiS_Pr->SiS_VBType & VB_SIS30xCLV)) return; if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToHiVision | SetCRT2ToYPbPr525750))) return; + if(SiS_Pr->ChipType >= XGI_20) return; + + if((SiS_Pr->ChipType >= SIS_661) && (SiS_Pr->SiS_ROMNew)) { + if(!(ROMAddr[0x61] & 0x04)) return; + } + if(ModeNo > 0x13) { resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; } @@ -7625,7 +7432,7 @@ SiS_SetGroup4_C_ELV(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, if(!(temp & 0x01)) { SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x3a,0xdf); SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xfc); - if((HwInfo->jChipType < SIS_661) && (!(SiS_Pr->SiS_ROMNew))) { + if((SiS_Pr->ChipType < SIS_661) && (!(SiS_Pr->SiS_ROMNew))) { SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xf8); } SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0xfb); @@ -7633,24 +7440,29 @@ SiS_SetGroup4_C_ELV(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) temp = 0x0002; else if(SiS_Pr->SiS_TVMode & TVSetHiVision) temp = 0x0400; else temp = 0x0402; - if((HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { + if((SiS_Pr->ChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { temp1 = 0; if(SiS_Pr->SiS_TVMode & TVAspect43) temp1 = 4; SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0f,0xfb,temp1); if(SiS_Pr->SiS_TVMode & TVAspect43LB) temp |= 0x01; SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0x7c,(temp & 0xff)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0xfb,(temp >> 8)); + if(ModeNo > 0x13) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x39,0xfd); + } } else { temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x3b) & 0x03; if(temp1 == 0x01) temp |= 0x01; if(temp1 == 0x03) temp |= 0x04; /* ? why not 0x10? */ SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xf8,(temp & 0xff)); - } - SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0xfb,(temp >> 8)); - if(ModeNo > 0x13) { - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x3b,0xfd); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0xfb,(temp >> 8)); + if(ModeNo > 0x13) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x3b,0xfd); + } } - if(HwInfo->jChipType >= SIS_661) { /* ? */ +#if 0 + if(SiS_Pr->ChipType >= SIS_661) { /* ? */ if(SiS_Pr->SiS_TVMode & TVAspect43) { if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { if(resinfo == SIS_RI_1024x768) { @@ -7663,29 +7475,30 @@ SiS_SetGroup4_C_ELV(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } } } +#endif + } + } #endif static void -SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +SiS_SetCRT2VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { - USHORT vclkindex; - USHORT temp, reg1, reg2; + unsigned short vclkindex, temp, reg1, reg2; if(SiS_Pr->UseCustomMode) { reg1 = SiS_Pr->CSR2B; reg2 = SiS_Pr->CSR2C; } else { - vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, - HwInfo); + vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); reg1 = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A; reg2 = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B; } - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { + if(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSet525p1024)) { SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,0x57); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,0x46); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1f,0xf6); @@ -7698,18 +7511,42 @@ SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0b,reg2); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x0a,reg1); } - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x12,0x00); - temp = 0x08; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) temp |= 0x20; - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,temp); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x12,0x00); + temp = 0x08; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) temp |= 0x20; + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,temp); +} + +static void +SiS_SetDualLinkEtc(struct SiS_Private *SiS_Pr) +{ + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISDUALLINK) { + if((SiS_CRT2IsLCD(SiS_Pr)) || + (SiS_IsVAMode(SiS_Pr))) { + if(SiS_Pr->SiS_LCDInfo & LCDDualLink) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c); + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,~0x20); + } + } + } + } + if(SiS_Pr->SiS_VBType & VB_SISEMI) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); +#ifdef SET_EMI + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); +#endif + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); + } } static void -SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +SiS_SetGroup4(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { - USHORT tempax,tempcx,tempbx,modeflag,temp,resinfo; - ULONG tempebx,tempeax,templong; + unsigned short tempax, tempcx, tempbx, modeflag, temp, resinfo; + unsigned int tempebx, tempeax, templong; if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; @@ -7722,38 +7559,24 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; } - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x24,0x0e); - } + if(SiS_Pr->ChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x24,0x0e); + } } } - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV)) { + if(SiS_Pr->SiS_VBType & (VB_SIS30xCLV | VB_SIS302LV)) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x10,0x9f); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x10,0x9f); } } - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - if(SiS_IsDualLink(SiS_Pr, HwInfo)) { - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c); - } else { - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,~0x20); - } - - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); -#ifdef SET_EMI - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); -#endif - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); - } - } - return; + SiS_SetDualLinkEtc(SiS_Pr); + return; } } @@ -7777,16 +7600,16 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_SetReg(SiS_Pr->SiS_Part4Port,0x15,temp); tempbx = SiS_Pr->SiS_VGAHDE; - if(modeflag & HalfDCLK) tempbx >>= 1; - if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + if(modeflag & HalfDCLK) tempbx >>= 1; + if(SiS_IsDualLink(SiS_Pr)) tempbx >>= 1; if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { temp = 0; if(tempbx > 800) temp = 0x60; } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { temp = 0; - if(tempbx == 1024) temp = 0xA0; - else if(tempbx > 1024) temp = 0xC0; + if(tempbx > 1024) temp = 0xC0; + else if(tempbx >= 960) temp = 0xA0; } else if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) { temp = 0; if(tempbx >= 1280) temp = 0x40; @@ -7796,8 +7619,13 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(tempbx >= 1024) temp = 0xA0; } + temp |= SiS_Pr->Init_P4_0E; + if(SiS_Pr->SiS_VBType & VB_SIS301) { - if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) temp |= 0x0A; + if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) { + temp &= 0xf0; + temp |= 0x0A; + } } SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0E,0x10,temp); @@ -7824,15 +7652,15 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, tempeax /= tempebx; if(templong) tempeax++; - temp = (USHORT)(tempeax & 0x000000FF); + temp = (unsigned short)(tempeax & 0x000000FF); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1B,temp); - temp = (USHORT)((tempeax & 0x0000FF00) >> 8); + temp = (unsigned short)((tempeax & 0x0000FF00) >> 8); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1A,temp); - temp = (USHORT)((tempeax >> 12) & 0x70); /* sic! */ + temp = (unsigned short)((tempeax >> 12) & 0x70); /* sic! */ temp |= (tempcx & 0x4F); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x19,temp); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1C,0x28); @@ -7840,23 +7668,26 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, tempbx = 0; if(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr750p)) tempbx = 0x08; tempax = SiS_Pr->SiS_VGAHDE; - if(modeflag & HalfDCLK) tempax >>= 1; - if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempax >>= 1; + if(modeflag & HalfDCLK) tempax >>= 1; + if(SiS_IsDualLink(SiS_Pr)) tempax >>= 1; if(tempax > 800) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { tempax -= 800; - } else { /* 651+301C: Only if TVNoHiviNoYPbPr */ + } else { tempbx = 0x08; - if(tempax == 1024) tempax *= 25; - else tempax *= 20; + if(tempax == 960) tempax *= 25; /* Correct */ + else if(tempax == 1024) tempax *= 25; + else tempax *= 20; temp = tempax % 32; tempax /= 32; if(temp) tempax++; tempax++; - if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) || - (SiS_Pr->SiS_TVMode & TVSetYPbPr525i)) { - if(resinfo == SIS_RI_1024x768) { - /* Otherwise white line at right edge */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(resinfo == SIS_RI_1024x768 || + resinfo == SIS_RI_1024x576 || + resinfo == SIS_RI_1280x1024 || + resinfo == SIS_RI_1280x720) { + /* Otherwise white line or garbage at right edge */ tempax = (tempax & 0xff00) | 0x20; } } @@ -7868,7 +7699,7 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1E,temp); temp = 0x0036; tempbx = 0xD0; - if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { + if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { temp = 0x0026; tempbx = 0xC0; /* See En/DisableBridge() */ } if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { @@ -7884,36 +7715,24 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x1F,tempbx,temp); tempbx = SiS_Pr->SiS_HT >> 1; - if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + if(SiS_IsDualLink(SiS_Pr)) tempbx >>= 1; tempbx -= 2; SiS_SetReg(SiS_Pr->SiS_Part4Port,0x22,tempbx); temp = (tempbx >> 5) & 0x38; SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0xC0,temp); - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { SiS_SetReg(SiS_Pr->SiS_Part4Port,0x24,0x0e); /* LCD-too-dark-error-source, see FinalizeLCD() */ } - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_IsDualLink(SiS_Pr, HwInfo)) { - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c); - } else { - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x27,~0x20); - } - } - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); -#ifdef SET_EMI - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); -#endif - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); - } } + SiS_SetDualLinkEtc(SiS_Pr); + } /* 301B */ - SiS_SetCRT2VCLK(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + SiS_SetCRT2VCLK(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } /*********************************************/ @@ -7921,8 +7740,7 @@ SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ static void -SiS_SetGroup5(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo) +SiS_SetGroup5(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; @@ -7930,7 +7748,7 @@ SiS_SetGroup5(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(SiS_Pr->SiS_ModeType == ModeVGA) { if(!(SiS_Pr->SiS_VBInfo & (SetInSlaveMode | LoadDACFlag))) { SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); - SiS_LoadDAC(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); + SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex); } } } @@ -7939,116 +7757,156 @@ SiS_SetGroup5(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /* MODIFY CRT1 GROUP FOR SLAVE MODE */ /*********************************************/ -static void -SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) -{ - USHORT tempah,i,modeflag,j; - USHORT ResIndex,DisplayType; - const SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL; +static BOOLEAN +SiS_GetLVDSCRT1Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex, unsigned short *ResIndex, + unsigned short *DisplayType) + { + unsigned short modeflag = 0; + BOOLEAN checkhd = TRUE; + + /* Pass 1:1 not supported here */ + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + (*ResIndex) &= 0x3F; + + if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + + (*DisplayType) = 80; + if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) { + (*DisplayType) = 82; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) (*DisplayType) = 84; + } + } + if((*DisplayType) != 84) { + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; + } + + } else { + + (*DisplayType = 0); + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_320x240_1: (*DisplayType) = 50; + checkhd = FALSE; + break; + case Panel_320x240_2: (*DisplayType) = 14; + break; + case Panel_320x240_3: (*DisplayType) = 18; + break; + case Panel_640x480: (*DisplayType) = 10; + break; + case Panel_1024x600: (*DisplayType) = 26; + break; + default: return TRUE; + } + + if(checkhd) { + if(modeflag & HalfDCLK) (*DisplayType)++; + } + + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x600) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) (*DisplayType) += 2; + } + + } + + return TRUE; +} - if(ModeNo <= 0x13) modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - else modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; +static void +SiS_ModCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) +{ + unsigned short tempah, i, modeflag, j, ResIndex, DisplayType; + const struct SiS_LVDSCRT1Data *LVDSCRT1Ptr=NULL; + static const unsigned short CRIdx[] = { + 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x10, 0x11, 0x15, 0x16 + }; if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || - (SiS_Pr->SiS_CustomT == CUT_PANEL848)) + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + (SiS_Pr->SiS_CustomT == CUT_PANEL856) ) return; + if(SiS_Pr->SiS_IF_DEF_LVDS) { + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return; + } + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return; + } else return; + + if(SiS_Pr->SiS_LCDInfo & LCDPass11) return; + + if(SiS_Pr->ChipType < SIS_315H) { + if(SiS_Pr->SiS_SetFlag & SetDOSMode) return; + } + if(!(SiS_GetLVDSCRT1Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, &ResIndex, &DisplayType))) { return; } - if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_SetFlag & SetDOSMode) return; + switch(DisplayType) { + case 50: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x240_1; break; /* xSTN */ + case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x240_2; break; /* xSTN */ + case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x240_2_H; break; /* xSTN */ + case 18: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x240_3; break; /* xSTN */ + case 19: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x240_3_H; break; /* xSTN */ + case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_1; break; + case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_1_H; break; +#if 0 /* Works better with calculated numbers */ + case 26: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1; break; + case 27: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1_H; break; + case 28: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2; break; + case 29: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2_H; break; +#endif + case 80: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC; break; + case 81: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC; break; + case 82: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL; break; + case 83: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL; break; + case 84: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1SOPAL; break; } - switch(DisplayType) { - case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1; break; - case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H; break; - case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2; break; - case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H; break; - case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1; break; - case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H; break; - case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2; break; - case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H; break; - case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1; break; - case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H; break; - case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2; break; - case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H; break; - case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1; break; - case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H; break; - case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1; break; - case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1_H; break; - case 16: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2; break; - case 17: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2_H; break; - case 18: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC; break; - case 19: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC; break; - case 20: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL; break; - case 21: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL; break; - case 22: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x480_1; break; /* FSTN */ - case 23: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1; break; - case 24: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1_H; break; - case 25: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2; break; - case 26: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2_H; break; - case 27: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1; break; - case 28: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1_H; break; - case 29: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2; break; - case 30: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2_H; break; - case 36: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1; break; - case 37: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1_H; break; - case 38: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2; break; - case 39: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2_H; break; - case 40: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_1; break; - case 41: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_1_H; break; - case 42: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_2; break; - case 43: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x768_2_H; break; - case 50: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_1; break; - case 51: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_1_H; break; - case 52: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_2; break; - case 53: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_2_H; break; - case 54: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_3; break; - case 55: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1640x480_3_H; break; - case 99: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1SOPAL; break; - default: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1; break; - } - - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); - - tempah = (LVDSCRT1Ptr + ResIndex)->CR[0]; - SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,tempah); - - for(i=0x02,j=1;i<=0x05;i++,j++){ - tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; - SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah); - } - for(i=0x06,j=5;i<=0x07;i++,j++){ - tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; - SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah); - } - for(i=0x10,j=7;i<=0x11;i++,j++){ - tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; - SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah); - } - for(i=0x15,j=9;i<=0x16;i++,j++){ - tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; - SiS_SetReg(SiS_Pr->SiS_P3d4,i,tempah); - } - for(i=0x0A,j=11;i<=0x0C;i++,j++){ - tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; - SiS_SetReg(SiS_Pr->SiS_P3c4,i,tempah); - } - - tempah = (LVDSCRT1Ptr + ResIndex)->CR[14]; - tempah &= 0xE0; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1f,tempah); - - tempah = (LVDSCRT1Ptr + ResIndex)->CR[14]; - tempah &= 0x01; - tempah <<= 5; - if(modeflag & DoubleScanMode) tempah |= 0x080; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah); + if(LVDSCRT1Ptr) { + + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); + + for(i = 0; i <= 10; i++) { + tempah = (LVDSCRT1Ptr + ResIndex)->CR[i]; + SiS_SetReg(SiS_Pr->SiS_P3d4,CRIdx[i],tempah); + } + + for(i = 0x0A, j = 11; i <= 0x0C; i++, j++) { + tempah = (LVDSCRT1Ptr + ResIndex)->CR[j]; + SiS_SetReg(SiS_Pr->SiS_P3c4,i,tempah); + } + + tempah = (LVDSCRT1Ptr + ResIndex)->CR[14] & 0xE0; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1f,tempah); + + if(ModeNo <= 0x13) modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + else modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + + tempah = ((LVDSCRT1Ptr + ResIndex)->CR[14] & 0x01) << 5; + if(modeflag & DoubleScanMode) tempah |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah); + + } else { + + SiS_CalcLCDACRT1Timing(SiS_Pr, ModeNo, ModeIdIndex); + + } } /*********************************************/ @@ -8056,24 +7914,24 @@ SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ static void -SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) +SiS_SetCRT2ECLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT clkbase, vclkindex=0; - UCHAR sr2b, sr2c; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short clkbase, vclkindex = 0; + unsigned char sr2b, sr2c; - if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) || (SiS_Pr->SiS_LCDInfo & LCDPass11)) { - SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); - if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK & 0x3f) == 2) { - RefreshRateTableIndex--; - } - vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, - RefreshRateTableIndex, HwInfo); - SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); + if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK == 2) { + RefreshRateTableIndex--; + } + vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; } else { - vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, - RefreshRateTableIndex, HwInfo); + vclkindex = SiS_GetVCLK2Ptr(SiS_Pr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); } sr2b = SiS_Pr->SiS_VCLKData[vclkindex].SR2B; @@ -8082,7 +7940,7 @@ SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { if(SiS_Pr->SiS_UseROM) { if(ROMAddr[0x220] & 0x01) { - sr2b = ROMAddr[0x227]; + sr2b = ROMAddr[0x227]; sr2c = ROMAddr[0x228]; } } @@ -8091,7 +7949,7 @@ SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, clkbase = 0x02B; if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - clkbase += 3; + clkbase += 3; } } @@ -8111,368 +7969,331 @@ SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, /*********************************************/ static void -SiS_SetCHTVReg(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex) +SiS_SetCHTVReg(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex) { -#if defined(SIS300) || defined(SIS315H) - USHORT temp, tempbx; -#endif - USHORT tempcl; - USHORT TVType, resindex; - const SiS_CHTVRegDataStruct *CHTVRegData = NULL; + unsigned short TVType, resindex; + const struct SiS_CHTVRegData *CHTVRegData = NULL; - if(ModeNo <= 0x13) - tempcl = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; - else - tempcl = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + if(ModeNo <= 0x13) + resindex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + else + resindex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - TVType = 0; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - TVType += 2; - if(SiS_Pr->SiS_ModeType > ModeVGA) { - if(SiS_Pr->SiS_CHSOverScan) TVType = 8; - } - if(SiS_Pr->SiS_TVMode & TVSetPALM) { - TVType = 4; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; - } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { - TVType = 6; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; - } - } - switch(TVType) { - case 0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break; - case 1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break; - case 2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL; break; - case 3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; - case 4: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALM; break; - case 5: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALM; break; - case 6: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALN; break; - case 7: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALN; break; - case 8: CHTVRegData = SiS_Pr->SiS_CHTVReg_SOPAL; break; - default: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; - } - resindex = tempcl & 0x3F; + resindex &= 0x3F; - if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { + TVType = 0; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + TVType += 2; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) TVType = 8; + } + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + TVType = 4; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; + } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { + TVType = 6; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; + } + } + + switch(TVType) { + case 0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break; + case 1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break; + case 2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL; break; + case 3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; + case 4: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALM; break; + case 5: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALM; break; + case 6: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALN; break; + case 7: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALN; break; + case 8: CHTVRegData = SiS_Pr->SiS_CHTVReg_SOPAL; break; + default: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; + } + + + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { #ifdef SIS300 - /* Chrontel 7005 - I assume that it does not come with a 315 series chip */ + /* Chrontel 7005 - I assume that it does not come with a 315 series chip */ - /* We don't support modes >800x600 */ - if (resindex > 5) return; + /* We don't support modes >800x600 */ + if (resindex > 5) return; - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - SiS_SetCH700x(SiS_Pr,0x4304); /* 0x40=76uA (PAL); 0x03=15bit non-multi RGB*/ - SiS_SetCH700x(SiS_Pr,0x6909); /* Black level for PAL (105)*/ - } else { - SiS_SetCH700x(SiS_Pr,0x0304); /* upper nibble=71uA (NTSC), 0x03=15bit non-multi RGB*/ - SiS_SetCH700x(SiS_Pr,0x7109); /* Black level for NTSC (113)*/ - } - - temp = CHTVRegData[resindex].Reg[0]; - tempbx=((temp&0x00FF)<<8)|0x00; /* Mode register */ - SiS_SetCH700x(SiS_Pr,tempbx); - temp = CHTVRegData[resindex].Reg[1]; - tempbx=((temp&0x00FF)<<8)|0x07; /* Start active video register */ - SiS_SetCH700x(SiS_Pr,tempbx); - temp = CHTVRegData[resindex].Reg[2]; - tempbx=((temp&0x00FF)<<8)|0x08; /* Position overflow register */ - SiS_SetCH700x(SiS_Pr,tempbx); - temp = CHTVRegData[resindex].Reg[3]; - tempbx=((temp&0x00FF)<<8)|0x0A; /* Horiz Position register */ - SiS_SetCH700x(SiS_Pr,tempbx); - temp = CHTVRegData[resindex].Reg[4]; - tempbx=((temp&0x00FF)<<8)|0x0B; /* Vertical Position register */ - SiS_SetCH700x(SiS_Pr,tempbx); - - /* Set minimum flicker filter for Luma channel (SR1-0=00), + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + SiS_SetCH700x(SiS_Pr,0x04,0x43); /* 0x40=76uA (PAL); 0x03=15bit non-multi RGB*/ + SiS_SetCH700x(SiS_Pr,0x09,0x69); /* Black level for PAL (105)*/ + } else { + SiS_SetCH700x(SiS_Pr,0x04,0x03); /* upper nibble=71uA (NTSC), 0x03=15bit non-multi RGB*/ + SiS_SetCH700x(SiS_Pr,0x09,0x71); /* Black level for NTSC (113)*/ + } + + SiS_SetCH700x(SiS_Pr,0x00,CHTVRegData[resindex].Reg[0]); /* Mode register */ + SiS_SetCH700x(SiS_Pr,0x07,CHTVRegData[resindex].Reg[1]); /* Start active video register */ + SiS_SetCH700x(SiS_Pr,0x08,CHTVRegData[resindex].Reg[2]); /* Position overflow register */ + SiS_SetCH700x(SiS_Pr,0x0a,CHTVRegData[resindex].Reg[3]); /* Horiz Position register */ + SiS_SetCH700x(SiS_Pr,0x0b,CHTVRegData[resindex].Reg[4]); /* Vertical Position register */ + + /* Set minimum flicker filter for Luma channel (SR1-0=00), minimum text enhancement (S3-2=10), maximum flicker filter for Chroma channel (S5-4=10) =00101000=0x28 (When reading, S1-0->S3-2, and S3-2->S1-0!) - */ - SiS_SetCH700x(SiS_Pr,0x2801); + */ + SiS_SetCH700x(SiS_Pr,0x01,0x28); - /* Set video bandwidth + /* Set video bandwidth High bandwith Luma composite video filter(S0=1) low bandwith Luma S-video filter (S2-1=00) disable peak filter in S-video channel (S3=0) high bandwidth Chroma Filter (S5-4=11) =00110001=0x31 - */ - SiS_SetCH700x(SiS_Pr,0xb103); /* old: 3103 */ + */ + SiS_SetCH700x(SiS_Pr,0x03,0xb1); /* old: 3103 */ - /* Register 0x3D does not exist in non-macrovision register map + /* Register 0x3D does not exist in non-macrovision register map (Maybe this is a macrovision register?) - */ + */ #ifndef SIS_CP - SiS_SetCH70xx(SiS_Pr,0x003D); + SiS_SetCH70xx(SiS_Pr,0x3d,0x00); #endif - /* Register 0x10 only contains 1 writable bit (S0) for sensing, - all other bits a read-only. Macrovision? - */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0010,0x1F); + /* Register 0x10 only contains 1 writable bit (S0) for sensing, + all other bits a read-only. Macrovision? + */ + SiS_SetCH70xxANDOR(SiS_Pr,0x10,0x00,0x1F); - /* Register 0x11 only contains 3 writable bits (S0-S2) for - contrast enhancement (set to 010 -> gain 1 Yout = 17/16*(Yin-30) ) - */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0211,0xF8); + /* Register 0x11 only contains 3 writable bits (S0-S2) for + contrast enhancement (set to 010 -> gain 1 Yout = 17/16*(Yin-30) ) + */ + SiS_SetCH70xxANDOR(SiS_Pr,0x11,0x02,0xF8); - /* Clear DSEN - */ - SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xEF); - - if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { /* ---- NTSC ---- */ - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) { - if(resindex == 0x04) { /* 640x480 overscan: Mode 16 */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE); /* ACIV on, no need to set FSCI */ - } else if(resindex == 0x05) { /* 800x600 overscan: Mode 23 */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0); /* 0x18-0x1f: FSCI 469,762,048 */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0C19,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x001A,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x001B,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x001D,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x001E,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x001F,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x0120,0xEF); /* Loop filter on for mode 23 */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE); /* ACIV off, need to set FSCI */ - } - } else { - if(resindex == 0x04) { /* ----- 640x480 underscan; Mode 17 */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE); - } else if(resindex == 0x05) { /* ----- 800x600 underscan: Mode 24 */ + /* Clear DSEN + */ + SiS_SetCH70xxANDOR(SiS_Pr,0x1c,0x00,0xEF); + + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { /* ---- NTSC ---- */ + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) { + if(resindex == 0x04) { /* 640x480 overscan: Mode 16 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x01,0xFE); /* ACIV on, no need to set FSCI */ + } else if(resindex == 0x05) { /* 800x600 overscan: Mode 23 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x18,0x01,0xF0); /* 0x18-0x1f: FSCI 469,762,048 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x19,0x0C,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1a,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1b,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1c,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1d,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1e,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1f,0x00,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x01,0xEF); /* Loop filter on for mode 23 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x00,0xFE); /* ACIV off, need to set FSCI */ + } + } else { + if(resindex == 0x04) { /* ----- 640x480 underscan; Mode 17 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x01,0xFE); + } else if(resindex == 0x05) { /* ----- 800x600 underscan: Mode 24 */ #if 0 - SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0); /* (FSCI was 0x1f1c71c7 - this is for mode 22) */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0919,0xF0); /* FSCI for mode 24 is 428,554,851 */ - SiS_SetCH70xxANDOR(SiS_Pr,0x081A,0xF0); /* 198b3a63 */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0b1B,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x041C,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x011D,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x061E,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x051F,0xF0); - SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off for mode 24 */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE); /* ACIV off, need to set FSCI */ -#endif /* All alternatives wrong (datasheet wrong?), don't use FSCI */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE); + SiS_SetCH70xxANDOR(SiS_Pr,0x18,0x01,0xF0); /* (FSCI was 0x1f1c71c7 - this is for mode 22) */ + SiS_SetCH70xxANDOR(SiS_Pr,0x19,0x09,0xF0); /* FSCI for mode 24 is 428,554,851 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x1a,0x08,0xF0); /* 198b3a63 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x1b,0x0b,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1c,0x04,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1d,0x01,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1e,0x06,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x1f,0x05,0xF0); + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off for mode 24 */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x00,0xFE); * ACIV off, need to set FSCI */ +#endif /* All alternatives wrong (datasheet wrong?), don't use FSCI */ + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x01,0xFE); + } } - } - } else { /* ---- PAL ---- */ - /* We don't play around with FSCI in PAL mode */ + } else { /* ---- PAL ---- */ + /* We don't play around with FSCI in PAL mode */ if(resindex == 0x04) { - SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE); /* ACIV on */ + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x01,0xFE); /* ACIV on */ } else { - SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); /* loop filter off */ - SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE); /* ACIV on */ + SiS_SetCH70xxANDOR(SiS_Pr,0x20,0x00,0xEF); /* loop filter off */ + SiS_SetCH70xxANDOR(SiS_Pr,0x21,0x01,0xFE); /* ACIV on */ } - } - + } + #endif /* 300 */ - } else { + } else { - /* Chrontel 7019 - assumed that it does not come with a 300 series chip */ + /* Chrontel 7019 - assumed that it does not come with a 300 series chip */ #ifdef SIS315H - /* We don't support modes >1024x768 */ - if (resindex > 6) return; - - temp = CHTVRegData[resindex].Reg[0]; - if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { - temp |= 0x10; - } - tempbx=((temp & 0x00FF) << 8) | 0x00; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[1]; - tempbx=((temp & 0x00FF) << 8) | 0x01; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[2]; - tempbx=((temp & 0x00FF) << 8) | 0x02; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[3]; - tempbx=((temp & 0x00FF) << 8) | 0x04; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[4]; - tempbx=((temp & 0x00FF) << 8) | 0x03; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[5]; - tempbx=((temp & 0x00FF) << 8) | 0x05; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[6]; - tempbx=((temp & 0x00FF) << 8) | 0x06; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[7]; - if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { - temp = 0x66; - } - tempbx=((temp & 0x00FF) << 8) | 0x07; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[8]; - tempbx=((temp & 0x00FF) << 8) | 0x08; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[9]; - tempbx=((temp & 0x00FF) << 8) | 0x15; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[10]; - tempbx=((temp & 0x00FF) << 8) | 0x1f; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[11]; - tempbx=((temp & 0x00FF) << 8) | 0x0c; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[12]; - tempbx=((temp & 0x00FF) << 8) | 0x0d; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[13]; - tempbx=((temp & 0x00FF) << 8) | 0x0e; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[14]; - tempbx=((temp & 0x00FF) << 8) | 0x0f; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = CHTVRegData[resindex].Reg[15]; - tempbx=((temp & 0x00FF) << 8) | 0x10; - SiS_SetCH701x(SiS_Pr,tempbx); - - temp = SiS_GetCH701x(SiS_Pr,0x21) & ~0x02; - /* D1 should be set for PAL, PAL-N and NTSC-J, - but I won't do that for PAL unless somebody - tells me to do so. Since the BIOS uses - non-default CIV values and blacklevels, - this might be compensated anyway. - */ - if(SiS_Pr->SiS_TVMode & (TVSetPALN | TVSetNTSCJ)) temp |= 0x02; - SiS_SetCH701x(SiS_Pr,((temp << 8) | 0x21)); + unsigned short temp; + + /* We don't support modes >1024x768 */ + if (resindex > 6) return; + + temp = CHTVRegData[resindex].Reg[0]; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) temp |= 0x10; + SiS_SetCH701x(SiS_Pr,0x00,temp); + + SiS_SetCH701x(SiS_Pr,0x01,CHTVRegData[resindex].Reg[1]); + SiS_SetCH701x(SiS_Pr,0x02,CHTVRegData[resindex].Reg[2]); + SiS_SetCH701x(SiS_Pr,0x04,CHTVRegData[resindex].Reg[3]); + SiS_SetCH701x(SiS_Pr,0x03,CHTVRegData[resindex].Reg[4]); + SiS_SetCH701x(SiS_Pr,0x05,CHTVRegData[resindex].Reg[5]); + SiS_SetCH701x(SiS_Pr,0x06,CHTVRegData[resindex].Reg[6]); + + temp = CHTVRegData[resindex].Reg[7]; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) temp = 0x66; + SiS_SetCH701x(SiS_Pr,0x07,temp); + + SiS_SetCH701x(SiS_Pr,0x08,CHTVRegData[resindex].Reg[8]); + SiS_SetCH701x(SiS_Pr,0x15,CHTVRegData[resindex].Reg[9]); + SiS_SetCH701x(SiS_Pr,0x1f,CHTVRegData[resindex].Reg[10]); + SiS_SetCH701x(SiS_Pr,0x0c,CHTVRegData[resindex].Reg[11]); + SiS_SetCH701x(SiS_Pr,0x0d,CHTVRegData[resindex].Reg[12]); + SiS_SetCH701x(SiS_Pr,0x0e,CHTVRegData[resindex].Reg[13]); + SiS_SetCH701x(SiS_Pr,0x0f,CHTVRegData[resindex].Reg[14]); + SiS_SetCH701x(SiS_Pr,0x10,CHTVRegData[resindex].Reg[15]); + + temp = SiS_GetCH701x(SiS_Pr,0x21) & ~0x02; + /* D1 should be set for PAL, PAL-N and NTSC-J, + but I won't do that for PAL unless somebody + tells me to do so. Since the BIOS uses + non-default CIV values and blacklevels, + this might be compensated anyway. + */ + if(SiS_Pr->SiS_TVMode & (TVSetPALN | TVSetNTSCJ)) temp |= 0x02; + SiS_SetCH701x(SiS_Pr,0x21,temp); #endif /* 315 */ - } + } #ifdef SIS_CP - SIS_CP_INIT301_CP3 + SIS_CP_INIT301_CP3 #endif } +#ifdef SIS315H /* ----------- 315 series only ---------- */ + void -SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr) { - USHORT temp; + unsigned short temp; - /* Enable Chrontel 7019 LCD panel backlight */ - if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - if(HwInfo->jChipType == SIS_740) { - SiS_SetCH701x(SiS_Pr,0x6566); - } else { - temp = SiS_GetCH701x(SiS_Pr,0x66); - temp |= 0x20; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66); - } - } + /* Enable Chrontel 7019 LCD panel backlight */ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_Pr->ChipType == SIS_740) { + SiS_SetCH701x(SiS_Pr,0x66,0x65); + } else { + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp |= 0x20; + SiS_SetCH701x(SiS_Pr,0x66,temp); + } + } } void -SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr) +SiS_Chrontel701xBLOff(struct SiS_Private *SiS_Pr) { - USHORT temp; + unsigned short temp; - /* Disable Chrontel 7019 LCD panel backlight */ - if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - temp = SiS_GetCH701x(SiS_Pr,0x66); - temp &= 0xDF; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66); - } + /* Disable Chrontel 7019 LCD panel backlight */ + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + temp = SiS_GetCH701x(SiS_Pr,0x66); + temp &= 0xDF; + SiS_SetCH701x(SiS_Pr,0x66,temp); + } } -#ifdef SIS315H /* ----------- 315 series only ---------- */ - static void -SiS_ChrontelPowerSequencing(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) -{ - UCHAR regtable[] = { 0x67, 0x68, 0x69, 0x6a, 0x6b }; - UCHAR table1024_740[] = { 0x01, 0x02, 0x01, 0x01, 0x01 }; - UCHAR table1400_740[] = { 0x01, 0x6e, 0x01, 0x01, 0x01 }; - UCHAR asus1024_740[] = { 0x19, 0x6e, 0x01, 0x19, 0x09 }; - UCHAR asus1400_740[] = { 0x19, 0x6e, 0x01, 0x19, 0x09 }; - UCHAR table1024_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 }; - UCHAR table1400_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 }; - UCHAR *tableptr = NULL; +SiS_ChrontelPowerSequencing(struct SiS_Private *SiS_Pr) +{ + static const unsigned char regtable[] = { 0x67, 0x68, 0x69, 0x6a, 0x6b }; + static const unsigned char table1024_740[] = { 0x01, 0x02, 0x01, 0x01, 0x01 }; + static const unsigned char table1400_740[] = { 0x01, 0x6e, 0x01, 0x01, 0x01 }; + static const unsigned char asus1024_740[] = { 0x19, 0x6e, 0x01, 0x19, 0x09 }; + static const unsigned char asus1400_740[] = { 0x19, 0x6e, 0x01, 0x19, 0x09 }; + static const unsigned char table1024_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 }; + static const unsigned char table1400_650[] = { 0x01, 0x02, 0x01, 0x01, 0x02 }; + const unsigned char *tableptr = NULL; int i; /* Set up Power up/down timing */ - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { - if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1024_740; - else tableptr = table1024_740; + if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1024_740; + else tableptr = table1024_740; } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || - (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) { if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1400_740; else tableptr = table1400_740; } else return; } else { if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { - tableptr = table1024_650; + tableptr = table1024_650; } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || - (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) { - tableptr = table1400_650; + tableptr = table1400_650; } else return; } for(i=0; i<5; i++) { - SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]); + SiS_SetCH701x(SiS_Pr, regtable[i], tableptr[i]); } } static void -SiS_SetCH701xForLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) -{ - UCHAR regtable[] = { 0x1c, 0x5f, 0x64, 0x6f, 0x70, 0x71, - 0x72, 0x73, 0x74, 0x76, 0x78, 0x7d, 0x66 }; - UCHAR table1024_740[] = { 0x60, 0x02, 0x00, 0x07, 0x40, 0xed, - 0xa3, 0xc8, 0xc7, 0xac, 0xe0, 0x02, 0x44 }; - UCHAR table1280_740[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, - 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 }; - UCHAR table1400_740[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, - 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 }; - UCHAR table1600_740[] = { 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3, - 0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a, 0x44 }; - UCHAR table1024_650[] = { 0x60, 0x02, 0x00, 0x07, 0x40, 0xed, - 0xa3, 0xc8, 0xc7, 0xac, 0x60, 0x02 }; - UCHAR table1280_650[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, - 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02 }; - UCHAR table1400_650[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xef, - 0xad, 0xdb, 0xf6, 0xac, 0x60, 0x02 }; - UCHAR table1600_650[] = { 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3, - 0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a }; - UCHAR *tableptr = NULL; - USHORT tempbh; +SiS_SetCH701xForLCD(struct SiS_Private *SiS_Pr) +{ + const unsigned char *tableptr = NULL; + unsigned short tempbh; int i; + static const unsigned char regtable[] = { + 0x1c, 0x5f, 0x64, 0x6f, 0x70, 0x71, + 0x72, 0x73, 0x74, 0x76, 0x78, 0x7d, 0x66 + }; + static const unsigned char table1024_740[] = { + 0x60, 0x02, 0x00, 0x07, 0x40, 0xed, + 0xa3, 0xc8, 0xc7, 0xac, 0xe0, 0x02, 0x44 + }; + static const unsigned char table1280_740[] = { + 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 + }; + static const unsigned char table1400_740[] = { + 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02, 0x44 + }; + static const unsigned char table1600_740[] = { + 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a, 0x44 + }; + static const unsigned char table1024_650[] = { + 0x60, 0x02, 0x00, 0x07, 0x40, 0xed, + 0xa3, 0xc8, 0xc7, 0xac, 0x60, 0x02 + }; + static const unsigned char table1280_650[] = { + 0x60, 0x03, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xdb, 0xf6, 0xac, 0xe0, 0x02 + }; + static const unsigned char table1400_650[] = { + 0x60, 0x03, 0x11, 0x00, 0x40, 0xef, + 0xad, 0xdb, 0xf6, 0xac, 0x60, 0x02 + }; + static const unsigned char table1600_650[] = { + 0x60, 0x04, 0x11, 0x00, 0x40, 0xe3, + 0xad, 0xde, 0xf6, 0xac, 0x60, 0x1a + }; - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tableptr = table1024_740; else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_740; else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_740; @@ -8499,138 +8320,139 @@ SiS_SetCH701xForLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } } - if(HwInfo->jChipType == SIS_740) tempbh = 0x0d; - else tempbh = 0x0c; + if(SiS_Pr->ChipType == SIS_740) tempbh = 0x0d; + else tempbh = 0x0c; for(i = 0; i < tempbh; i++) { - SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]); + SiS_SetCH701x(SiS_Pr, regtable[i], tableptr[i]); } - SiS_ChrontelPowerSequencing(SiS_Pr,HwInfo); + SiS_ChrontelPowerSequencing(SiS_Pr); tempbh = SiS_GetCH701x(SiS_Pr,0x1e); tempbh |= 0xc0; - SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1e); + SiS_SetCH701x(SiS_Pr,0x1e,tempbh); - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { tempbh = SiS_GetCH701x(SiS_Pr,0x1c); tempbh &= 0xfb; - SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1c); + SiS_SetCH701x(SiS_Pr,0x1c,tempbh); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x03); tempbh = SiS_GetCH701x(SiS_Pr,0x64); tempbh |= 0x40; - SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x64); + SiS_SetCH701x(SiS_Pr,0x64,tempbh); tempbh = SiS_GetCH701x(SiS_Pr,0x03); tempbh &= 0x3f; - SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x03); + SiS_SetCH701x(SiS_Pr,0x03,tempbh); } } static void -SiS_ChrontelResetVSync(SiS_Private *SiS_Pr) +SiS_ChrontelResetVSync(struct SiS_Private *SiS_Pr) { unsigned char temp, temp1; temp1 = SiS_GetCH701x(SiS_Pr,0x49); - SiS_SetCH701x(SiS_Pr,0x3e49); + SiS_SetCH701x(SiS_Pr,0x49,0x3e); temp = SiS_GetCH701x(SiS_Pr,0x47); temp &= 0x7f; /* Use external VSYNC */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); - SiS_LongDelay(SiS_Pr,3); + SiS_SetCH701x(SiS_Pr,0x47,temp); + SiS_LongDelay(SiS_Pr, 3); temp = SiS_GetCH701x(SiS_Pr,0x47); temp |= 0x80; /* Use internal VSYNC */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); - SiS_SetCH701x(SiS_Pr,(temp1 << 8) | 0x49); + SiS_SetCH701x(SiS_Pr,0x47,temp); + SiS_SetCH701x(SiS_Pr,0x49,temp1); } static void -SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_Chrontel701xOn(struct SiS_Private *SiS_Pr) { - USHORT temp; + unsigned short temp; if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { temp = SiS_GetCH701x(SiS_Pr,0x1c); temp |= 0x04; /* Invert XCLK phase */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x1c); + SiS_SetCH701x(SiS_Pr,0x1c,temp); } - if(SiS_IsYPbPr(SiS_Pr, HwInfo)) { + if(SiS_IsYPbPr(SiS_Pr)) { temp = SiS_GetCH701x(SiS_Pr,0x01); temp &= 0x3f; temp |= 0x80; /* Enable YPrPb (HDTV) */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x01); + SiS_SetCH701x(SiS_Pr,0x01,temp); } - if(SiS_IsChScart(SiS_Pr, HwInfo)) { + if(SiS_IsChScart(SiS_Pr)) { temp = SiS_GetCH701x(SiS_Pr,0x01); temp &= 0x3f; temp |= 0xc0; /* Enable SCART + CVBS */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x01); + SiS_SetCH701x(SiS_Pr,0x01,temp); } - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { SiS_ChrontelResetVSync(SiS_Pr); - SiS_SetCH701x(SiS_Pr,0x2049); /* Enable TV path */ + SiS_SetCH701x(SiS_Pr,0x49,0x20); /* Enable TV path */ } else { - SiS_SetCH701x(SiS_Pr,0x2049); /* Enable TV path */ + SiS_SetCH701x(SiS_Pr,0x49,0x20); /* Enable TV path */ temp = SiS_GetCH701x(SiS_Pr,0x49); - if(SiS_IsYPbPr(SiS_Pr,HwInfo)) { + if(SiS_IsYPbPr(SiS_Pr)) { temp = SiS_GetCH701x(SiS_Pr,0x73); temp |= 0x60; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x73); + SiS_SetCH701x(SiS_Pr,0x73,temp); } temp = SiS_GetCH701x(SiS_Pr,0x47); temp &= 0x7f; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); - SiS_LongDelay(SiS_Pr,2); + SiS_SetCH701x(SiS_Pr,0x47,temp); + SiS_LongDelay(SiS_Pr, 2); temp = SiS_GetCH701x(SiS_Pr,0x47); temp |= 0x80; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); + SiS_SetCH701x(SiS_Pr,0x47,temp); } } } static void -SiS_Chrontel701xOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_Chrontel701xOff(struct SiS_Private *SiS_Pr) { - USHORT temp; + unsigned short temp; /* Complete power down of LVDS */ if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { - if(HwInfo->jChipType == SIS_740) { - SiS_LongDelay(SiS_Pr,1); - SiS_GenericDelay(SiS_Pr,0x16ff); - SiS_SetCH701x(SiS_Pr,0xac76); - SiS_SetCH701x(SiS_Pr,0x0066); + if(SiS_Pr->ChipType == SIS_740) { + SiS_LongDelay(SiS_Pr, 1); + SiS_GenericDelay(SiS_Pr, 5887); + SiS_SetCH701x(SiS_Pr,0x76,0xac); + SiS_SetCH701x(SiS_Pr,0x66,0x00); } else { - SiS_LongDelay(SiS_Pr,2); + SiS_LongDelay(SiS_Pr, 2); temp = SiS_GetCH701x(SiS_Pr,0x76); temp &= 0xfc; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76); - SiS_SetCH701x(SiS_Pr,0x0066); + SiS_SetCH701x(SiS_Pr,0x76,temp); + SiS_SetCH701x(SiS_Pr,0x66,0x00); } } } static void -SiS_ChrontelResetDB(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_ChrontelResetDB(struct SiS_Private *SiS_Pr) { - USHORT temp; + unsigned short temp; - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { temp = SiS_GetCH701x(SiS_Pr,0x4a); /* Version ID */ temp &= 0x01; if(!temp) { - if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo)) { + if(SiS_WeHaveBacklightCtrl(SiS_Pr)) { temp = SiS_GetCH701x(SiS_Pr,0x49); - SiS_SetCH701x(SiS_Pr,0x3e49); + SiS_SetCH701x(SiS_Pr,0x49,0x3e); } + /* Reset Chrontel 7019 datapath */ - SiS_SetCH701x(SiS_Pr,0x1048); - SiS_LongDelay(SiS_Pr,1); - SiS_SetCH701x(SiS_Pr,0x1848); + SiS_SetCH701x(SiS_Pr,0x48,0x10); + SiS_LongDelay(SiS_Pr, 1); + SiS_SetCH701x(SiS_Pr,0x48,0x18); - if(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo)) { + if(SiS_WeHaveBacklightCtrl(SiS_Pr)) { SiS_ChrontelResetVSync(SiS_Pr); - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x49); + SiS_SetCH701x(SiS_Pr,0x49,temp); } } else { @@ -8638,72 +8460,72 @@ SiS_ChrontelResetDB(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /* Clear/set/clear GPIO */ temp = SiS_GetCH701x(SiS_Pr,0x5c); temp &= 0xef; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c); + SiS_SetCH701x(SiS_Pr,0x5c,temp); temp = SiS_GetCH701x(SiS_Pr,0x5c); temp |= 0x10; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c); + SiS_SetCH701x(SiS_Pr,0x5c,temp); temp = SiS_GetCH701x(SiS_Pr,0x5c); temp &= 0xef; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x5c); + SiS_SetCH701x(SiS_Pr,0x5c,temp); temp = SiS_GetCH701x(SiS_Pr,0x61); if(!temp) { - SiS_SetCH701xForLCD(SiS_Pr, HwInfo); + SiS_SetCH701xForLCD(SiS_Pr); } } } else { /* 650 */ /* Reset Chrontel 7019 datapath */ - SiS_SetCH701x(SiS_Pr,0x1048); - SiS_LongDelay(SiS_Pr,1); - SiS_SetCH701x(SiS_Pr,0x1848); + SiS_SetCH701x(SiS_Pr,0x48,0x10); + SiS_LongDelay(SiS_Pr, 1); + SiS_SetCH701x(SiS_Pr,0x48,0x18); } } static void -SiS_ChrontelInitTVVSync(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_ChrontelInitTVVSync(struct SiS_Private *SiS_Pr) { - USHORT temp; + unsigned short temp; - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { - if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo)) { + if(SiS_WeHaveBacklightCtrl(SiS_Pr)) { SiS_ChrontelResetVSync(SiS_Pr); } } else { - SiS_SetCH701x(SiS_Pr,0xaf76); /* Power up LVDS block */ + SiS_SetCH701x(SiS_Pr,0x76,0xaf); /* Power up LVDS block */ temp = SiS_GetCH701x(SiS_Pr,0x49); temp &= 1; if(temp != 1) { /* TV block powered? (0 = yes, 1 = no) */ temp = SiS_GetCH701x(SiS_Pr,0x47); temp &= 0x70; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); /* enable VSYNC */ - SiS_LongDelay(SiS_Pr,3); + SiS_SetCH701x(SiS_Pr,0x47,temp); /* enable VSYNC */ + SiS_LongDelay(SiS_Pr, 3); temp = SiS_GetCH701x(SiS_Pr,0x47); temp |= 0x80; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47); /* disable VSYNC */ + SiS_SetCH701x(SiS_Pr,0x47,temp); /* disable VSYNC */ } } } static void -SiS_ChrontelDoSomething3(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo) +SiS_ChrontelDoSomething3(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { - USHORT temp,temp1; + unsigned short temp,temp1; - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { temp = SiS_GetCH701x(SiS_Pr,0x61); if(temp < 1) { temp++; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61); + SiS_SetCH701x(SiS_Pr,0x61,temp); } - SiS_SetCH701x(SiS_Pr,0x4566); /* Panel power on */ - SiS_SetCH701x(SiS_Pr,0xaf76); /* All power on */ - SiS_LongDelay(SiS_Pr,1); - SiS_GenericDelay(SiS_Pr,0x16ff); + SiS_SetCH701x(SiS_Pr,0x66,0x45); /* Panel power on */ + SiS_SetCH701x(SiS_Pr,0x76,0xaf); /* All power on */ + SiS_LongDelay(SiS_Pr, 1); + SiS_GenericDelay(SiS_Pr, 5887); } else { /* 650 */ @@ -8711,38 +8533,38 @@ SiS_ChrontelDoSomething3(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_INFO HwInfo temp = SiS_GetCH701x(SiS_Pr,0x61); if(temp < 2) { temp++; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61); + SiS_SetCH701x(SiS_Pr,0x61,temp); temp1 = 1; } - SiS_SetCH701x(SiS_Pr,0xac76); + SiS_SetCH701x(SiS_Pr,0x76,0xac); temp = SiS_GetCH701x(SiS_Pr,0x66); temp |= 0x5f; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66); + SiS_SetCH701x(SiS_Pr,0x66,temp); if(ModeNo > 0x13) { - if(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo)) { - SiS_GenericDelay(SiS_Pr,0x3ff); + if(SiS_WeHaveBacklightCtrl(SiS_Pr)) { + SiS_GenericDelay(SiS_Pr, 1023); } else { - SiS_GenericDelay(SiS_Pr,0x2ff); + SiS_GenericDelay(SiS_Pr, 767); } } else { if(!temp1) - SiS_GenericDelay(SiS_Pr,0x2ff); + SiS_GenericDelay(SiS_Pr, 767); } temp = SiS_GetCH701x(SiS_Pr,0x76); temp |= 0x03; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76); + SiS_SetCH701x(SiS_Pr,0x76,temp); temp = SiS_GetCH701x(SiS_Pr,0x66); temp &= 0x7f; - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66); - SiS_LongDelay(SiS_Pr,1); + SiS_SetCH701x(SiS_Pr,0x66,temp); + SiS_LongDelay(SiS_Pr, 1); } } static void -SiS_ChrontelDoSomething2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_ChrontelDoSomething2(struct SiS_Private *SiS_Pr) { - USHORT temp,tempcl,tempch; + unsigned short temp,tempcl,tempch; SiS_LongDelay(SiS_Pr, 1); tempcl = 3; @@ -8753,87 +8575,87 @@ SiS_ChrontelDoSomething2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) temp &= 0x04; /* PLL stable? -> bail out */ if(temp == 0x04) break; - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { /* Power down LVDS output, PLL normal operation */ - SiS_SetCH701x(SiS_Pr,0xac76); + SiS_SetCH701x(SiS_Pr,0x76,0xac); } - SiS_SetCH701xForLCD(SiS_Pr,HwInfo); + SiS_SetCH701xForLCD(SiS_Pr); if(tempcl == 0) { if(tempch == 3) break; - SiS_ChrontelResetDB(SiS_Pr,HwInfo); + SiS_ChrontelResetDB(SiS_Pr); tempcl = 3; tempch++; } tempcl--; temp = SiS_GetCH701x(SiS_Pr,0x76); temp &= 0xfb; /* Reset PLL */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76); - SiS_LongDelay(SiS_Pr,2); + SiS_SetCH701x(SiS_Pr,0x76,temp); + SiS_LongDelay(SiS_Pr, 2); temp = SiS_GetCH701x(SiS_Pr,0x76); temp |= 0x04; /* PLL normal operation */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76); - if(HwInfo->jChipType == SIS_740) { - SiS_SetCH701x(SiS_Pr,0xe078); /* PLL loop filter */ + SiS_SetCH701x(SiS_Pr,0x76,temp); + if(SiS_Pr->ChipType == SIS_740) { + SiS_SetCH701x(SiS_Pr,0x78,0xe0); /* PLL loop filter */ } else { - SiS_SetCH701x(SiS_Pr,0x6078); + SiS_SetCH701x(SiS_Pr,0x78,0x60); } - SiS_LongDelay(SiS_Pr,2); + SiS_LongDelay(SiS_Pr, 2); } while(0); - SiS_SetCH701x(SiS_Pr,0x0077); /* MV? */ + SiS_SetCH701x(SiS_Pr,0x77,0x00); /* MV? */ } static void -SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_ChrontelDoSomething1(struct SiS_Private *SiS_Pr) { - USHORT temp; + unsigned short temp; temp = SiS_GetCH701x(SiS_Pr,0x03); temp |= 0x80; /* Set datapath 1 to TV */ temp &= 0xbf; /* Set datapath 2 to LVDS */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03); + SiS_SetCH701x(SiS_Pr,0x03,temp); - if(HwInfo->jChipType == SIS_740) { + if(SiS_Pr->ChipType == SIS_740) { temp = SiS_GetCH701x(SiS_Pr,0x1c); temp &= 0xfb; /* Normal XCLK phase */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x1c); + SiS_SetCH701x(SiS_Pr,0x1c,temp); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,0x03); temp = SiS_GetCH701x(SiS_Pr,0x64); temp |= 0x40; /* ? Bit not defined */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x64); + SiS_SetCH701x(SiS_Pr,0x64,temp); temp = SiS_GetCH701x(SiS_Pr,0x03); temp &= 0x3f; /* D1 input to both LVDS and TV */ - SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03); + SiS_SetCH701x(SiS_Pr,0x03,temp); if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) { - SiS_SetCH701x(SiS_Pr,0x4063); /* LVDS off */ + SiS_SetCH701x(SiS_Pr,0x63,0x40); /* LVDS off */ SiS_LongDelay(SiS_Pr, 1); - SiS_SetCH701x(SiS_Pr,0x0063); /* LVDS on */ - SiS_ChrontelResetDB(SiS_Pr, HwInfo); - SiS_ChrontelDoSomething2(SiS_Pr, HwInfo); - SiS_ChrontelDoSomething3(SiS_Pr, 0, HwInfo); + SiS_SetCH701x(SiS_Pr,0x63,0x00); /* LVDS on */ + SiS_ChrontelResetDB(SiS_Pr); + SiS_ChrontelDoSomething2(SiS_Pr); + SiS_ChrontelDoSomething3(SiS_Pr, 0); } else { temp = SiS_GetCH701x(SiS_Pr,0x66); if(temp != 0x45) { - SiS_ChrontelResetDB(SiS_Pr, HwInfo); - SiS_ChrontelDoSomething2(SiS_Pr, HwInfo); - SiS_ChrontelDoSomething3(SiS_Pr, 0, HwInfo); + SiS_ChrontelResetDB(SiS_Pr); + SiS_ChrontelDoSomething2(SiS_Pr); + SiS_ChrontelDoSomething3(SiS_Pr, 0); } } } else { /* 650 */ - SiS_ChrontelResetDB(SiS_Pr,HwInfo); - SiS_ChrontelDoSomething2(SiS_Pr,HwInfo); + SiS_ChrontelResetDB(SiS_Pr); + SiS_ChrontelDoSomething2(SiS_Pr); temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34); - SiS_ChrontelDoSomething3(SiS_Pr,temp,HwInfo); - SiS_SetCH701x(SiS_Pr,0xaf76); /* All power on, LVDS normal operation */ + SiS_ChrontelDoSomething3(SiS_Pr,temp); + SiS_SetCH701x(SiS_Pr,0x76,0xaf); /* All power on, LVDS normal operation */ } @@ -8845,15 +8667,12 @@ SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /*********************************************/ BOOLEAN -SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) +SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { #ifdef SIS300 - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; -#endif - USHORT ModeIdIndex, RefreshRateTableIndex; -#if 0 - USHORT temp; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; #endif + unsigned short ModeIdIndex, RefreshRateTableIndex; SiS_Pr->SiS_SetFlag |= ProgrammingCRT2; @@ -8866,37 +8685,37 @@ SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) /* Used for shifting CR33 */ SiS_Pr->SiS_SelectCRT2Rate = 4; - SiS_UnLockCRT2(SiS_Pr, HwInfo); + SiS_UnLockCRT2(SiS_Pr); - RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + RefreshRateTableIndex = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex); SiS_SaveCRT2Info(SiS_Pr,ModeNo); if(SiS_Pr->SiS_SetFlag & LowModeTests) { - SiS_DisableBridge(SiS_Pr,HwInfo); - if((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (HwInfo->jChipType == SIS_730)) { + SiS_DisableBridge(SiS_Pr); + if((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->ChipType == SIS_730)) { SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,0x80); } - SiS_SetCRT2ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_SetCRT2ModeRegs(SiS_Pr, ModeNo, ModeIdIndex); } if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) { - SiS_LockCRT2(SiS_Pr, HwInfo); + SiS_LockCRT2(SiS_Pr); SiS_DisplayOn(SiS_Pr); return TRUE; } - SiS_GetCRT2Data(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + SiS_GetCRT2Data(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); /* Set up Panel Link for LVDS and LCDA */ SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0; if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) || ((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) || - ((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) { - SiS_GetLVDSDesData(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + ((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS30xBLV)) ) { + SiS_GetLVDSDesData(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } -#ifdef LINUX_XF86 +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "(init301: LCDHDES 0x%03x LCDVDES 0x%03x)\n", SiS_Pr->SiS_LCDHDES, SiS_Pr->SiS_LCDVDES); xf86DrvMsg(0, X_INFO, "(init301: HDE 0x%03x VDE 0x%03x)\n", SiS_Pr->SiS_HDE, SiS_Pr->SiS_VDE); @@ -8907,86 +8726,79 @@ SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) #endif if(SiS_Pr->SiS_SetFlag & LowModeTests) { - SiS_SetGroup1(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + SiS_SetGroup1(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(SiS_Pr->SiS_SetFlag & LowModeTests) { - SiS_SetGroup2(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + SiS_SetGroup2(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); #ifdef SIS315H - SiS_SetGroup2_C_ELV(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + SiS_SetGroup2_C_ELV(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); #endif - SiS_SetGroup3(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); - SiS_SetGroup4(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + SiS_SetGroup3(SiS_Pr, ModeNo, ModeIdIndex); + SiS_SetGroup4(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); #ifdef SIS315H - SiS_SetGroup4_C_ELV(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); + SiS_SetGroup4_C_ELV(SiS_Pr, ModeNo, ModeIdIndex); #endif - SiS_SetGroup5(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_SetGroup5(SiS_Pr, ModeNo, ModeIdIndex); - SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo); + SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex); - /* For 301BDH (Panel link initialization): */ - if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { - if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) { - if(!((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10)))) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex, - RefreshRateTableIndex,HwInfo); - } - } - } - SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex, - RefreshRateTableIndex,HwInfo); - } - } + /* For 301BDH (Panel link initialization): */ + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + + if(!((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10)))) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SiS_ModCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + } + SiS_SetCRT2ECLK(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + } + } } else { - SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo); + SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex); - if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { - SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwInfo); - } + SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex); - SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwInfo); + SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex); - if(SiS_Pr->SiS_SetFlag & LowModeTests) { - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { + if(SiS_Pr->SiS_SetFlag & LowModeTests) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { #ifdef SIS315H - SiS_SetCH701xForLCD(SiS_Pr,HwInfo); + SiS_SetCH701xForLCD(SiS_Pr); #endif - } - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - SiS_SetCHTVReg(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex); - } - } - } + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + SiS_SetCHTVReg(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex); + } + } + } } #ifdef SIS300 - if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->ChipType < SIS_315H) { if(SiS_Pr->SiS_SetFlag & LowModeTests) { if(SiS_Pr->SiS_UseOEM) { if((SiS_Pr->SiS_UseROM) && (SiS_Pr->SiS_UseOEM == -1)) { if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { - SiS_OEM300Setting(SiS_Pr,HwInfo,ModeNo,ModeIdIndex, - RefreshRateTableIndex); + SiS_OEM300Setting(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } } else { - SiS_OEM300Setting(SiS_Pr,HwInfo,ModeNo,ModeIdIndex, - RefreshRateTableIndex); + SiS_OEM300Setting(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } } if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { - SetOEMLCDData2(SiS_Pr, HwInfo, ModeNo, ModeIdIndex,RefreshRateTableIndex); + SetOEMLCDData2(SiS_Pr, ModeNo, ModeIdIndex,RefreshRateTableIndex); } SiS_DisplayOn(SiS_Pr); } @@ -8995,21 +8807,21 @@ SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) #endif #ifdef SIS315H - if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->ChipType >= SIS_315H) { if(SiS_Pr->SiS_SetFlag & LowModeTests) { - if(HwInfo->jChipType < SIS_661) { - SiS_FinalizeLCD(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); - SiS_OEM310Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex); + if(SiS_Pr->ChipType < SIS_661) { + SiS_FinalizeLCD(SiS_Pr, ModeNo, ModeIdIndex); + SiS_OEM310Setting(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } else { - SiS_OEM661Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex); + SiS_OEM661Setting(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex); } - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40); } } #endif if(SiS_Pr->SiS_SetFlag & LowModeTests) { - SiS_EnableBridge(SiS_Pr, HwInfo); + SiS_EnableBridge(SiS_Pr); } SiS_DisplayOn(SiS_Pr); @@ -9017,15 +8829,15 @@ SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* Disable LCD panel when using TV */ - SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFF,0x0C); + SiS_SetRegSR11ANDOR(SiS_Pr,0xFF,0x0C); } else { /* Disable TV when using LCD */ - SiS_SetCH70xxANDOR(SiS_Pr,0x010E,0xF8); + SiS_SetCH70xxANDOR(SiS_Pr,0x0e,0x01,0xf8); } } if(SiS_Pr->SiS_SetFlag & LowModeTests) { - SiS_LockCRT2(SiS_Pr,HwInfo); + SiS_LockCRT2(SiS_Pr); } return TRUE; @@ -9037,13 +8849,13 @@ SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) /*********************************************/ void -SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_SiS30xBLOn(struct SiS_Private *SiS_Pr) { /* Switch on LCD backlight on SiS30xLV */ SiS_DDC2Delay(SiS_Pr,0xff00); if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) { SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); - SiS_WaitVBRetrace(SiS_Pr,HwInfo); + SiS_WaitVBRetrace(SiS_Pr); } if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x01)) { SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01); @@ -9051,12 +8863,11 @@ SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } void -SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_SiS30xBLOff(struct SiS_Private *SiS_Pr) { /* Switch off LCD backlight on SiS30xLV */ SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE); - SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); - SiS_DDC2Delay(SiS_Pr,0xe000); + SiS_DDC2Delay(SiS_Pr,0xff00); } /*********************************************/ @@ -9064,7 +8875,7 @@ SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) /*********************************************/ static void -SiS_SetupDDCN(SiS_Private *SiS_Pr) +SiS_SetupDDCN(struct SiS_Private *SiS_Pr) { SiS_Pr->SiS_DDC_NData = ~SiS_Pr->SiS_DDC_Data; SiS_Pr->SiS_DDC_NClk = ~SiS_Pr->SiS_DDC_Clk; @@ -9075,12 +8886,12 @@ SiS_SetupDDCN(SiS_Private *SiS_Pr) } #ifdef SIS300 -static UCHAR * -SiS_SetTrumpBlockLoop(SiS_Private *SiS_Pr, UCHAR *dataptr) +static unsigned char * +SiS_SetTrumpBlockLoop(struct SiS_Private *SiS_Pr, unsigned char *dataptr) { int i, j, num; - USHORT tempah,temp; - UCHAR *mydataptr; + unsigned short tempah,temp; + unsigned char *mydataptr; for(i=0; i<20; i++) { /* Do 20 attempts to write */ mydataptr = dataptr; @@ -9088,7 +8899,7 @@ SiS_SetTrumpBlockLoop(SiS_Private *SiS_Pr, UCHAR *dataptr) if(!num) return mydataptr; if(i) { SiS_SetStop(SiS_Pr); - SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT*2); + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT * 2); } if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ tempah = SiS_Pr->SiS_DDC_DeviceAddr; @@ -9110,12 +8921,12 @@ SiS_SetTrumpBlockLoop(SiS_Private *SiS_Pr, UCHAR *dataptr) } static BOOLEAN -SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr) +SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr) { SiS_Pr->SiS_DDC_DeviceAddr = 0xF0; /* DAB (Device Address Byte) */ SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ - SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ - SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ SiS_SetupDDCN(SiS_Pr); SiS_SetSwitchDDC2(SiS_Pr); @@ -9124,8 +8935,10 @@ SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr) dataptr = SiS_SetTrumpBlockLoop(SiS_Pr, dataptr); if(!dataptr) return FALSE; } +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "Trumpion block success\n"); +#endif #endif return TRUE; } @@ -9139,155 +8952,121 @@ SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr) */ static BOOLEAN -SiS_SetChReg(SiS_Private *SiS_Pr, USHORT tempbx, USHORT myor) +SiS_SetChReg(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val, unsigned short myor) { - USHORT tempah,temp,i; + unsigned short temp, i; for(i=0; i<20; i++) { /* Do 20 attempts to write */ if(i) { - SiS_SetStop(SiS_Pr); - SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); - } - if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ - tempah = SiS_Pr->SiS_DDC_DeviceAddr; - temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write DAB (S0=0=write) */ - if(temp) continue; /* (ERROR: no ack) */ - tempah = tempbx & 0x00FF; /* Write RAB */ - tempah |= myor; /* (700x: set bit 7, see datasheet) */ - temp = SiS_WriteDDC2Data(SiS_Pr,tempah); - if(temp) continue; /* (ERROR: no ack) */ - tempah = (tempbx & 0xFF00) >> 8; - temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write data */ - if(temp) continue; /* (ERROR: no ack) */ - if(SiS_SetStop(SiS_Pr)) continue; /* Set stop condition */ + SiS_SetStop(SiS_Pr); + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT * 4); + } + if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ + temp = SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_DeviceAddr); /* Write DAB (S0=0=write) */ + if(temp) continue; /* (ERROR: no ack) */ + temp = SiS_WriteDDC2Data(SiS_Pr, (reg | myor)); /* Write RAB (700x: set bit 7, see datasheet) */ + if(temp) continue; /* (ERROR: no ack) */ + temp = SiS_WriteDDC2Data(SiS_Pr, val); /* Write data */ + if(temp) continue; /* (ERROR: no ack) */ + if(SiS_SetStop(SiS_Pr)) continue; /* Set stop condition */ SiS_Pr->SiS_ChrontelInit = 1; return TRUE; } return FALSE; } -#if 0 -#ifdef SIS300 -/* Write Trumpion register */ -static void -SiS_SetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx) -{ - SiS_Pr->SiS_DDC_DeviceAddr = 0xF0; /* DAB (Device Address Byte) */ - SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ - SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ - SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ - SiS_SetupDDCN(SiS_Pr); - SiS_SetChReg(SiS_Pr, tempbx, 0); -} -#endif -#endif - /* Write to Chrontel 700x */ -/* Parameter is [Data (S15-S8) | Register no (S7-S0)] */ void -SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx) +SiS_SetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val) { SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB (Device Address Byte) */ + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); + if(!(SiS_Pr->SiS_ChrontelInit)) { SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ - SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ - SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ SiS_SetupDDCN(SiS_Pr); } - if( (!(SiS_SetChReg(SiS_Pr, tempbx, 0x80))) && + if( (!(SiS_SetChReg(SiS_Pr, reg, val, 0x80))) && (!(SiS_Pr->SiS_ChrontelInit)) ) { - SiS_Pr->SiS_DDC_Index = 0x0a; /* Bit 7 = SC; Bit 6 = SD */ - SiS_Pr->SiS_DDC_Data = 0x80; /* Bitmask in IndexReg for Data */ - SiS_Pr->SiS_DDC_Clk = 0x40; /* Bitmask in IndexReg for Clk */ + SiS_Pr->SiS_DDC_Index = 0x0a; + SiS_Pr->SiS_DDC_Data = 0x80; + SiS_Pr->SiS_DDC_Clk = 0x40; SiS_SetupDDCN(SiS_Pr); - SiS_SetChReg(SiS_Pr, tempbx, 0x80); + SiS_SetChReg(SiS_Pr, reg, val, 0x80); } } /* Write to Chrontel 701x */ /* Parameter is [Data (S15-S8) | Register no (S7-S0)] */ void -SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx) +SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val) { SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ - SiS_Pr->SiS_DDC_Data = 0x08; /* Bitmask in IndexReg for Data */ - SiS_Pr->SiS_DDC_Clk = 0x04; /* Bitmask in IndexReg for Clk */ + SiS_Pr->SiS_DDC_Data = 0x08; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x04; /* Bitmask in IndexReg for Clk */ SiS_SetupDDCN(SiS_Pr); - SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB (Device Address Byte) */ - SiS_SetChReg(SiS_Pr, tempbx, 0); + SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB (Device Address Byte) */ + SiS_SetChReg(SiS_Pr, reg, val, 0); } -static void -SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx) +#ifdef SIS_LINUX_KERNEL +static +#endif +void +SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val) { if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) - SiS_SetCH700x(SiS_Pr,tempbx); + SiS_SetCH700x(SiS_Pr, reg, val); else - SiS_SetCH701x(SiS_Pr,tempbx); + SiS_SetCH701x(SiS_Pr, reg, val); } -static USHORT -SiS_GetChReg(SiS_Private *SiS_Pr, USHORT myor) +static unsigned short +SiS_GetChReg(struct SiS_Private *SiS_Pr, unsigned short myor) { - USHORT tempah,temp,i; + unsigned short tempah, temp, i; for(i=0; i<20; i++) { /* Do 20 attempts to read */ if(i) { - SiS_SetStop(SiS_Pr); - SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); - } - if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ - tempah = SiS_Pr->SiS_DDC_DeviceAddr; - temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write DAB (S0=0=write) */ - if(temp) continue; /* (ERROR: no ack) */ - tempah = SiS_Pr->SiS_DDC_ReadAddr | myor; /* Write RAB (700x: | 0x80) */ - temp = SiS_WriteDDC2Data(SiS_Pr,tempah); - if(temp) continue; /* (ERROR: no ack) */ - if (SiS_SetStart(SiS_Pr)) continue; /* Re-start */ - tempah = SiS_Pr->SiS_DDC_DeviceAddr | 0x01;/* DAB | 0x01 = Read */ - temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* DAB (S0=1=read) */ - if(temp) continue; /* (ERROR: no ack) */ - tempah = SiS_ReadDDC2Data(SiS_Pr,tempah); /* Read byte */ - if(SiS_SetStop(SiS_Pr)) continue; /* Stop condition */ + SiS_SetStop(SiS_Pr); + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT * 4); + } + if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ + temp = SiS_WriteDDC2Data(SiS_Pr,SiS_Pr->SiS_DDC_DeviceAddr); /* Write DAB (S0=0=write) */ + if(temp) continue; /* (ERROR: no ack) */ + temp = SiS_WriteDDC2Data(SiS_Pr,SiS_Pr->SiS_DDC_ReadAddr | myor); /* Write RAB (700x: | 0x80) */ + if(temp) continue; /* (ERROR: no ack) */ + if (SiS_SetStart(SiS_Pr)) continue; /* Re-start */ + temp = SiS_WriteDDC2Data(SiS_Pr,SiS_Pr->SiS_DDC_DeviceAddr | 0x01);/* DAB (S0=1=read) */ + if(temp) continue; /* (ERROR: no ack) */ + tempah = SiS_ReadDDC2Data(SiS_Pr); /* Read byte */ + if(SiS_SetStop(SiS_Pr)) continue; /* Stop condition */ SiS_Pr->SiS_ChrontelInit = 1; - return(tempah); + return tempah; } return 0xFFFF; } -#if 0 -#ifdef SIS300 -/* Read from Trumpion */ -static USHORT -SiS_GetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx) -{ - SiS_Pr->SiS_DDC_DeviceAddr = 0xF0; /* DAB */ - SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ - SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ - SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ - SiS_SetupDDCN(SiS_Pr); - SiS_Pr->SiS_DDC_ReadAddr = tempbx; - return(SiS_GetChReg(SiS_Pr,0)); -} -#endif -#endif - /* Read from Chrontel 700x */ /* Parameter is [Register no (S7-S0)] */ -USHORT -SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx) +unsigned short +SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short tempbx) { - USHORT result; + unsigned short result; SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB */ + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); + if(!(SiS_Pr->SiS_ChrontelInit)) { SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ - SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ - SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ SiS_SetupDDCN(SiS_Pr); } @@ -9303,52 +9082,69 @@ SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx) result = SiS_GetChReg(SiS_Pr,0x80); } - return(result); + return result; } /* Read from Chrontel 701x */ /* Parameter is [Register no (S7-S0)] */ -USHORT -SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx) +unsigned short +SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short tempbx) { SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ - SiS_Pr->SiS_DDC_Data = 0x08; /* Bitmask in IndexReg for Data */ - SiS_Pr->SiS_DDC_Clk = 0x04; /* Bitmask in IndexReg for Clk */ + SiS_Pr->SiS_DDC_Data = 0x08; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x04; /* Bitmask in IndexReg for Clk */ SiS_SetupDDCN(SiS_Pr); SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB */ SiS_Pr->SiS_DDC_ReadAddr = tempbx; - return(SiS_GetChReg(SiS_Pr,0)); + return SiS_GetChReg(SiS_Pr,0); } /* Read from Chrontel 70xx */ /* Parameter is [Register no (S7-S0)] */ -static USHORT -SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx) +#ifdef SIS_LINUX_KERNEL +static +#endif +unsigned short +SiS_GetCH70xx(struct SiS_Private *SiS_Pr, unsigned short tempbx) { if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) - return(SiS_GetCH700x(SiS_Pr, tempbx)); + return SiS_GetCH700x(SiS_Pr, tempbx); else - return(SiS_GetCH701x(SiS_Pr, tempbx)); + return SiS_GetCH701x(SiS_Pr, tempbx); +} + +void +SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg, + unsigned char myor, unsigned short myand) +{ + unsigned short tempbl; + + tempbl = (SiS_GetCH70xx(SiS_Pr, (reg & 0xFF)) & myand) | myor; + SiS_SetCH70xx(SiS_Pr, reg, tempbl); } /* Our own DDC functions */ -static USHORT -SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine, - USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32) +#ifndef SIS_XORG_XF86 +static +#endif +unsigned short +SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, + unsigned short adaptnum, unsigned short DDCdatatype, BOOLEAN checkcr32, + unsigned int VBFlags2) { unsigned char ddcdtype[] = { 0xa0, 0xa0, 0xa0, 0xa2, 0xa6 }; unsigned char flag, cr32; - USHORT temp = 0, myadaptnum = adaptnum; + unsigned short temp = 0, myadaptnum = adaptnum; if(adaptnum != 0) { - if(!(VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0xFFFF; - if((VBFlags & VB_30xBDH) && (adaptnum == 1)) return 0xFFFF; - } - + if(!(VBFlags2 & VB2_SISTMDSBRIDGE)) return 0xFFFF; + if((VBFlags2 & VB2_30xBDH) && (adaptnum == 1)) return 0xFFFF; + } + /* adapternum for SiS bridges: 0 = CRT1, 1 = LCD, 2 = VGA2 */ - + SiS_Pr->SiS_ChrontelInit = 0; /* force re-detection! */ SiS_Pr->SiS_DDC_SecAddr = 0; @@ -9360,7 +9156,7 @@ SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine, cr32 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x32); #if 0 - if(VBFlags & VB_SISBRIDGE) { + if(VBFlags2 & VB2_SISBRIDGE) { if(myadaptnum == 0) { if(!(cr32 & 0x20)) { myadaptnum = 2; @@ -9376,20 +9172,20 @@ SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine, #endif if(VGAEngine == SIS_300_VGA) { /* 300 series */ - + if(myadaptnum != 0) { flag = 0; - if(VBFlags & VB_SISBRIDGE) { + if(VBFlags2 & VB2_SISBRIDGE) { SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port; SiS_Pr->SiS_DDC_Index = 0x0f; } } - if(!(VBFlags & VB_301)) { + if(!(VBFlags2 & VB2_301)) { if((cr32 & 0x80) && (checkcr32)) { if(myadaptnum >= 1) { if(!(cr32 & 0x08)) { - myadaptnum = 1; + myadaptnum = 1; if(!(cr32 & 0x10)) return 0xFFFF; } } @@ -9401,17 +9197,17 @@ SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine, } else { /* 315/330 series */ - /* here we simplify: 0 = CRT1, 1 = CRT2 (VGA, LCD) */ + /* here we simplify: 0 = CRT1, 1 = CRT2 (VGA, LCD) */ - if(VBFlags & VB_SISBRIDGE) { + if(VBFlags2 & VB2_SISBRIDGE) { if(myadaptnum == 2) { myadaptnum = 1; - } + } } if(myadaptnum == 1) { - flag = 0; - if(VBFlags & VB_SISBRIDGE) { + flag = 0; + if(VBFlags2 & VB2_SISBRIDGE) { SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port; SiS_Pr->SiS_DDC_Index = 0x0f; } @@ -9429,93 +9225,96 @@ SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine, temp = myadaptnum; if(myadaptnum == 1) { temp = 0; - if(VBFlags & VB_LVDS) flag = 0xff; + if(VBFlags2 & VB2_LVDS) flag = 0xff; } if(flag) temp = 0; } - + SiS_Pr->SiS_DDC_Data = 0x02 << temp; SiS_Pr->SiS_DDC_Clk = 0x01 << temp; SiS_SetupDDCN(SiS_Pr); +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "DDC Port %x Index %x Shift %d\n", SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index, temp); #endif - +#endif return 0; } -static USHORT -SiS_WriteDABDDC(SiS_Private *SiS_Pr) +static unsigned short +SiS_WriteDABDDC(struct SiS_Private *SiS_Pr) { if(SiS_SetStart(SiS_Pr)) return 0xFFFF; if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_DeviceAddr)) { - return 0xFFFF; + return 0xFFFF; } if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_SecAddr)) { - return 0xFFFF; + return 0xFFFF; } - return(0); + return 0; } -static USHORT -SiS_PrepareReadDDC(SiS_Private *SiS_Pr) +static unsigned short +SiS_PrepareReadDDC(struct SiS_Private *SiS_Pr) { if(SiS_SetStart(SiS_Pr)) return 0xFFFF; if(SiS_WriteDDC2Data(SiS_Pr, (SiS_Pr->SiS_DDC_DeviceAddr | 0x01))) { - return 0xFFFF; + return 0xFFFF; } - return(0); + return 0; } -static USHORT -SiS_PrepareDDC(SiS_Private *SiS_Pr) +static unsigned short +SiS_PrepareDDC(struct SiS_Private *SiS_Pr) { if(SiS_WriteDABDDC(SiS_Pr)) SiS_WriteDABDDC(SiS_Pr); - if(SiS_PrepareReadDDC(SiS_Pr)) return(SiS_PrepareReadDDC(SiS_Pr)); - return(0); + if(SiS_PrepareReadDDC(SiS_Pr)) return (SiS_PrepareReadDDC(SiS_Pr)); + return 0; } static void -SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno) +SiS_SendACK(struct SiS_Private *SiS_Pr, unsigned short yesno) { SiS_SetSCLKLow(SiS_Pr); if(yesno) { SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, SiS_Pr->SiS_DDC_Data); } else { SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, 0); } SiS_SetSCLKHigh(SiS_Pr); } -static USHORT -SiS_DoProbeDDC(SiS_Private *SiS_Pr) +static unsigned short +SiS_DoProbeDDC(struct SiS_Private *SiS_Pr) { unsigned char mask, value; - USHORT temp, ret=0; + unsigned short temp, ret=0; BOOLEAN failed = FALSE; SiS_SetSwitchDDC2(SiS_Pr); if(SiS_PrepareDDC(SiS_Pr)) { SiS_SetStop(SiS_Pr); +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "Probe: Prepare failed\n"); #endif - return(0xFFFF); +#endif + return 0xFFFF; } mask = 0xf0; value = 0x20; if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) { - temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0); + temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr); SiS_SendACK(SiS_Pr, 0); if(temp == 0) { mask = 0xff; @@ -9523,20 +9322,24 @@ SiS_DoProbeDDC(SiS_Private *SiS_Pr) } else { failed = TRUE; ret = 0xFFFF; +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "Probe: Read 1 failed\n"); +#endif #endif } } if(failed == FALSE) { - temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0); + temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr); SiS_SendACK(SiS_Pr, 1); temp &= mask; if(temp == value) ret = 0; else { ret = 0xFFFF; +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "Probe: Read 2 failed\n"); +#endif #endif if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) { if(temp == 0x30) ret = 0; @@ -9544,13 +9347,16 @@ SiS_DoProbeDDC(SiS_Private *SiS_Pr) } } SiS_SetStop(SiS_Pr); - return(ret); + return ret; } -static USHORT -SiS_ProbeDDC(SiS_Private *SiS_Pr) +#ifndef SIS_XORG_XF86 +static +#endif +unsigned short +SiS_ProbeDDC(struct SiS_Private *SiS_Pr) { - USHORT flag; + unsigned short flag; flag = 0x180; SiS_Pr->SiS_DDC_DeviceAddr = 0xa0; @@ -9560,16 +9366,19 @@ SiS_ProbeDDC(SiS_Private *SiS_Pr) SiS_Pr->SiS_DDC_DeviceAddr = 0xa6; if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x10; if(!(flag & 0x1a)) flag = 0; - return(flag); + return flag; } -static USHORT -SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, unsigned char *buffer) +#ifndef SIS_XORG_XF86 +static +#endif +unsigned short +SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype, unsigned char *buffer) { - USHORT flag, length, i; + unsigned short flag, length, i; unsigned char chksum,gotcha; - if(DDCdatatype > 4) return 0xFFFF; + if(DDCdatatype > 4) return 0xFFFF; flag = 0; SiS_SetSwitchDDC2(SiS_Pr); @@ -9579,21 +9388,21 @@ SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, unsigned char *buffer) chksum = 0; gotcha = 0; for(i=0; i<length; i++) { - buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0); + buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr); chksum += buffer[i]; gotcha |= buffer[i]; SiS_SendACK(SiS_Pr, 0); } - buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0); + buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr); chksum += buffer[i]; SiS_SendACK(SiS_Pr, 1); - if(gotcha) flag = (USHORT)chksum; + if(gotcha) flag = (unsigned short)chksum; else flag = 0xFFFF; } else { flag = 0xFFFF; } SiS_SetStop(SiS_Pr); - return(flag); + return flag; } /* Our private DDC functions @@ -9617,17 +9426,25 @@ SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, unsigned char *buffer) if DDCdatatype = 0: Returns supported DDC modes */ -USHORT -SiS_HandleDDC(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine, - USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer) +unsigned short +SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, + unsigned short adaptnum, unsigned short DDCdatatype, unsigned char *buffer, + unsigned int VBFlags2) { - unsigned char sr1f,cr17=1; - USHORT result; + unsigned char sr1f, cr17=1; + unsigned short result; - if(adaptnum > 2) return 0xFFFF; - if(DDCdatatype > 4) return 0xFFFF; - if((!(VBFlags & VB_VIDEOBRIDGE)) && (adaptnum > 0)) return 0xFFFF; - if(SiS_InitDDCRegs(SiS_Pr, VBFlags, VGAEngine, adaptnum, DDCdatatype, FALSE) == 0xFFFF) return 0xFFFF; + if(adaptnum > 2) + return 0xFFFF; + + if(DDCdatatype > 4) + return 0xFFFF; + + if((!(VBFlags2 & VB2_VIDEOBRIDGE)) && (adaptnum > 0)) + return 0xFFFF; + + if(SiS_InitDDCRegs(SiS_Pr, VBFlags, VGAEngine, adaptnum, DDCdatatype, FALSE, VBFlags2) == 0xFFFF) + return 0xFFFF; sr1f = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f); SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1f,0x3f,0x04); @@ -9656,10 +9473,12 @@ SiS_HandleDDC(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine, (buffer[4] == 0xff) && (buffer[5] == 0xff) && (buffer[6] == 0xff) && (buffer[7] == 0x00) && (buffer[0x12] == 1)) { - if(adaptnum == 1) { - if(!(buffer[0x14] & 0x80)) result = 0xFFFE; - } else { - if(buffer[0x14] & 0x80) result = 0xFFFE; + if(!SiS_Pr->DDCPortMixup) { + if(adaptnum == 1) { + if(!(buffer[0x14] & 0x80)) result = 0xFFFE; + } else { + if(buffer[0x14] & 0x80) result = 0xFFFE; + } } } } @@ -9671,832 +9490,10 @@ SiS_HandleDDC(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine, return result; } -#ifdef LINUX_XF86 - -static BOOLEAN -checkedid1(unsigned char *buffer) -{ - /* Check header */ - if((buffer[0] != 0x00) || - (buffer[1] != 0xff) || - (buffer[2] != 0xff) || - (buffer[3] != 0xff) || - (buffer[4] != 0xff) || - (buffer[5] != 0xff) || - (buffer[6] != 0xff) || - (buffer[7] != 0x00)) - return FALSE; - - /* Check EDID version and revision */ - if((buffer[0x12] != 1) || (buffer[0x13] > 4)) return FALSE; - - /* Check week of manufacture for sanity */ - if(buffer[0x10] > 53) return FALSE; - - /* Check year of manufacture for sanity */ - if(buffer[0x11] > 40) return FALSE; - - return TRUE; -} - -static BOOLEAN -checkedid2(unsigned char *buffer) -{ - USHORT year = buffer[6] | (buffer[7] << 8); - - /* Check EDID version */ - if((buffer[0] & 0xf0) != 0x20) return FALSE; - - /* Check week of manufacture for sanity */ - if(buffer[5] > 53) return FALSE; - - /* Check year of manufacture for sanity */ - if((year != 0) && ((year < 1990) || (year > 2030))) return FALSE; - - return TRUE; -} - -/* Sense the LCD parameters (CR36, CR37) via DDC */ -/* SiS30x(B) only */ -USHORT -SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS) -{ - USHORT DDCdatatype, paneltype, flag, xres=0, yres=0; - USHORT index, myindex, lumsize, numcodes, panelvendor, panelproduct; - int maxx=0, maxy=0, prefx=0, prefy=0; - unsigned char cr37=0, seekcode; - BOOLEAN checkexpand = FALSE; - BOOLEAN havesync = FALSE; - BOOLEAN indb = FALSE; - int retry, i; - unsigned char buffer[256]; - - for(i=0; i<7; i++) SiS_Pr->CP_DataValid[i] = FALSE; - SiS_Pr->CP_HaveCustomData = FALSE; - SiS_Pr->CP_MaxX = SiS_Pr->CP_MaxY = SiS_Pr->CP_MaxClock = 0; - SiS_Pr->CP_PreferredX = SiS_Pr->CP_PreferredY = 0; - SiS_Pr->CP_PreferredIndex = -1; - SiS_Pr->CP_PrefClock = 0; - SiS_Pr->PanelSelfDetected = FALSE; - - if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0; - if(pSiS->VBFlags & VB_30xBDH) return 0; - - if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 1, 0, FALSE) == 0xFFFF) return 0; - - SiS_Pr->SiS_DDC_SecAddr = 0x00; - - /* Probe supported DA's */ - flag = SiS_ProbeDDC(SiS_Pr); -#ifdef TWDEBUG - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO, - "CRT2 DDC capabilities 0x%x\n", flag); -#endif - if(flag & 0x10) { - SiS_Pr->SiS_DDC_DeviceAddr = 0xa6; /* EDID V2 (FP) */ - DDCdatatype = 4; - } else if(flag & 0x08) { - SiS_Pr->SiS_DDC_DeviceAddr = 0xa2; /* EDID V2 (P&D-D Monitor) */ - DDCdatatype = 3; - } else if(flag & 0x02) { - SiS_Pr->SiS_DDC_DeviceAddr = 0xa0; /* EDID V1 */ - DDCdatatype = 1; - } else return 0; /* no DDC support (or no device attached) */ - - /* Read the entire EDID */ - retry = 2; - do { - if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "CRT2: DDC read failed (attempt %d), %s\n", - (3-retry), (retry == 1) ? "giving up" : "retrying"); - retry--; - if(retry == 0) return 0xFFFF; - } else break; - } while(1); - -#ifdef TWDEBUG - for(i=0; i<256; i+=16) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - buffer[i], buffer[i+1], buffer[i+2], buffer[i+3], - buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7], - buffer[i+8], buffer[i+9], buffer[i+10], buffer[i+11], - buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]); - } -#endif - - /* Analyze EDID and retrieve LCD panel information */ - paneltype = 0; - switch(DDCdatatype) { - case 1: /* Analyze EDID V1 */ - /* Catch a few clear cases: */ - if(!(checkedid1(buffer))) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "LCD sense: EDID corrupt\n"); - return 0; - } - - if(!(buffer[0x14] & 0x80)) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "LCD sense: Attached display expects analog input (0x%02x)\n", - buffer[0x14]); - return 0; - } - - if((buffer[0x18] & 0x18) != 0x08) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "LCD sense: Warning: Attached display is not of RGB but of %s type (0x%02x)\n", - ((buffer[0x18] & 0x18) == 0x00) ? "monochrome/greyscale" : - ( ((buffer[0x18] & 0x18) == 0x10) ? "non-RGB multicolor" : - "undefined"), - buffer[0x18]); - } - - /* Now analyze the first Detailed Timing Block and see - * if the preferred timing mode is stored there. If so, - * check if this is a standard panel for which we already - * know the timing. - */ - - paneltype = Panel_Custom; - checkexpand = FALSE; - - panelvendor = buffer[9] | (buffer[8] << 8); - panelproduct = buffer[10] | (buffer[11] << 8); - - /* Overrule bogus preferred modes from database */ - if((indb = SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) { - if(prefx) SiS_Pr->CP_PreferredX = xres = prefx; - if(prefy) SiS_Pr->CP_PreferredY = yres = prefy; - } - - if(buffer[0x18] & 0x02) { - - USHORT pclk = (buffer[0x36] | (buffer[0x37] << 8)); - USHORT phb = (buffer[0x39] | ((buffer[0x3a] & 0x0f) << 8)); - USHORT pvb = (buffer[0x3c] | ((buffer[0x3d] & 0x0f) << 8)); - - if(!xres) SiS_Pr->CP_PreferredX = xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4); - if(!yres) SiS_Pr->CP_PreferredY = yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4); - - switch(xres) { -#if 0 /* Treat as custom */ - case 800: - if(yres == 600) { - paneltype = Panel_800x600; - checkexpand = TRUE; - } - break; -#endif - case 1024: - if(yres == 768) { - paneltype = Panel_1024x768; - checkexpand = TRUE; - } - break; - case 1280: - if(yres == 1024) { - paneltype = Panel_1280x1024; - checkexpand = TRUE; - } else if(yres == 960) { - if(pSiS->VGAEngine == SIS_300_VGA) { - paneltype = Panel300_1280x960; - } else { - paneltype = Panel310_1280x960; - } - } else if(yres == 768) { - if( (pclk == 8100) && - (phb == (1688 - 1280)) && - (pvb == (802 - 768)) ) { - paneltype = Panel_1280x768; - checkexpand = FALSE; - cr37 |= 0x10; - } - } else if(yres == 800) { - if( (pclk == 6900) && - (phb == (1408 - 1280)) && - (pvb == (816 - 800)) ) { - paneltype = Panel_1280x800; - } - } - break; - case 1400: - if(pSiS->VGAEngine == SIS_315_VGA) { - if(yres == 1050) { - paneltype = Panel310_1400x1050; - checkexpand = TRUE; - } - } - break; - case 1600: - if(pSiS->VGAEngine == SIS_315_VGA) { - if(pSiS->VBFlags & VB_301C) { - if(yres == 1200) { - paneltype = Panel310_1600x1200; - checkexpand = TRUE; - } - } - } - break; - } - - /* Save sync: This is used if "Pass 1:1" is off; in this case - * we always use the panel's native mode = this "preferred mode" - * we just have been analysing. Hence, we also need its sync. - */ - if((buffer[0x47] & 0x18) == 0x18) { - cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20); - havesync = TRUE; - } else { - /* What now? There is no digital separate output timing... */ - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING, - "LCD sense: Unable to retrieve Sync polarity information\n"); - cr37 |= 0xc0; /* Default */ - } - - } - - /* Check against our database; eg. Sanyo Z2 projector reports - * 1024x768 as preferred mode, although it supports 1280x720 - * natively in non-HDCP mode. Treat such wrongly reporting - * panels as custom and fixup actual maximum resolutions. - */ - if(paneltype != Panel_Custom) { - if(indb) { - paneltype = Panel_Custom; - SiS_Pr->CP_MaxX = maxx; - SiS_Pr->CP_MaxY = maxy; - /* Leave preferred unchanged (MUST contain a valid mode!) */ - } - } - - /* If we still don't know what panel this is, we take it - * as a custom panel and derive the timing data from the - * detailed timing blocks - */ - if(paneltype == Panel_Custom) { - - int i, temp, base = 0x36; - unsigned long estpack; - const unsigned short estx[] = { - 720, 720, 640, 640, 640, 640, 800, 800, - 800, 800, 832,1024,1024,1024,1024,1280, - 1152 - }; - const unsigned short esty[] = { - 400, 400, 480, 480, 480, 480, 600, 600, - 600, 600, 624, 768, 768, 768, 768,1024, - 870 - }; - const int estclk[] = { - 0, 0, 25100, 0, 31500, 31500, 36100, 40000, - 50100, 49500, 0, 0, 65100, 75200, 78700,135200, - 0 - }; - - paneltype = 0; - SiS_Pr->CP_Supports64048075 = TRUE; - - /* Find the maximum resolution */ - - /* 1. From Established timings */ - estpack = (buffer[0x23] << 9) | (buffer[0x24] << 1) | ((buffer[0x25] >> 7) & 0x01); - for(i=16; i>=0; i--) { - if(estpack & (1 << i)) { - if(estx[16 - i] > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = estx[16 - i]; - if(esty[16 - i] > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = esty[16 - i]; - if(estclk[16 - i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = estclk[16 - i]; - } - } - - /* By default we drive the LCD at 75Hz in 640x480 mode; if - * the panel does not provide this mode, use 60hz - */ - if(!(buffer[0x23] & 0x04)) SiS_Pr->CP_Supports64048075 = FALSE; - - /* 2. From Standard Timings */ - for(i=0x26; i < 0x36; i+=2) { - if((buffer[i] != 0x01) && (buffer[i+1] != 0x01)) { - temp = (buffer[i] + 31) * 8; - if(temp > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = temp; - switch((buffer[i+1] & 0xc0) >> 6) { - case 0x03: temp = temp * 9 / 16; break; - case 0x02: temp = temp * 4 / 5; break; - case 0x01: temp = temp * 3 / 4; break; - } - if(temp > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = temp; - } - } - - /* Now extract the Detailed Timings and convert them into modes */ - - for(i = 0; i < 4; i++, base += 18) { - - /* Is this a detailed timing block or a monitor descriptor? */ - if(buffer[base] || buffer[base+1] || buffer[base+2]) { - - xres = buffer[base+2] | ((buffer[base+4] & 0xf0) << 4); - yres = buffer[base+5] | ((buffer[base+7] & 0xf0) << 4); - - SiS_Pr->CP_HDisplay[i] = xres; - SiS_Pr->CP_HSyncStart[i] = xres + (buffer[base+8] | ((buffer[base+11] & 0xc0) << 2)); - SiS_Pr->CP_HSyncEnd[i] = SiS_Pr->CP_HSyncStart[i] + (buffer[base+9] | ((buffer[base+11] & 0x30) << 4)); - SiS_Pr->CP_HTotal[i] = xres + (buffer[base+3] | ((buffer[base+4] & 0x0f) << 8)); - SiS_Pr->CP_HBlankStart[i] = xres + 1; - SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i]; - - SiS_Pr->CP_VDisplay[i] = yres; - SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[base+10] & 0xf0) >> 4) | ((buffer[base+11] & 0x0c) << 2)); - SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[base+10] & 0x0f) | ((buffer[base+11] & 0x03) << 4)); - SiS_Pr->CP_VTotal[i] = yres + (buffer[base+6] | ((buffer[base+7] & 0x0f) << 8)); - SiS_Pr->CP_VBlankStart[i] = yres + 1; - SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i]; - - SiS_Pr->CP_Clock[i] = (buffer[base] | (buffer[base+1] << 8)) * 10; - - SiS_Pr->CP_DataValid[i] = TRUE; - - /* Sort out invalid timings, interlace and too high clocks */ - if((SiS_Pr->CP_HDisplay[i] & 7) || - (SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i]) || - (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i]) || - (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i]) || - (SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i]) || - (SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i]) || - (SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i]) || - (SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i]) || - (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i]) || - (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i]) || - (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i]) || - (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i]) || - (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i]) || - (((pSiS->VBFlags & VB_301C) && (SiS_Pr->CP_Clock[i] > 162500)) || - ((!(pSiS->VBFlags & VB_301C)) && - ((SiS_Pr->CP_Clock[i] > 108200) || (SiS_Pr->CP_VDisplay[i] > 1024) || - (SiS_Pr->CP_HDisplay[i] > 1600)))) || - (buffer[base+17] & 0x80)) { - - SiS_Pr->CP_DataValid[i] = FALSE; - - } else { - - SiS_Pr->CP_HaveCustomData = TRUE; - - if(xres > SiS_Pr->CP_MaxX) SiS_Pr->CP_MaxX = xres; - if(yres > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = yres; - if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i]; - - if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) { - SiS_Pr->CP_PreferredIndex = i; - SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C); - SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1; - } - - /* Extract the sync polarisation information. This only works - * if the Flags indicate a digital separate output. - */ - if((buffer[base+17] & 0x18) == 0x18) { - SiS_Pr->CP_HSync_P[i] = (buffer[base+17] & 0x02) ? TRUE : FALSE; - SiS_Pr->CP_VSync_P[i] = (buffer[base+17] & 0x04) ? TRUE : FALSE; - SiS_Pr->CP_SyncValid[i] = TRUE; - if((i == SiS_Pr->CP_PreferredIndex) && (!havesync)) { - cr37 |= ((((buffer[base+17] & 0x06) ^ 0x06) << 5) | 0x20); - havesync = TRUE; - } - } else { - SiS_Pr->CP_SyncValid[i] = FALSE; - } - - } - - } else if((!buffer[base]) && (!buffer[base+1]) && (!buffer[base+2]) && (!buffer[base+4])) { - - /* Maximum pixclock from Monitor Range Limits */ - if((buffer[base+3] == 0xfd) && (buffer[base+9] != 0xff)) { - int maxclk = buffer[base+9] * 10; - /* More than 170 is not supported anyway */ - if(maxclk <= 170) SiS_Pr->CP_MaxClock = maxclk * 1000; - } - - } - - } - - if(SiS_Pr->CP_MaxX && SiS_Pr->CP_MaxY) { - paneltype = Panel_Custom; - checkexpand = FALSE; - cr37 |= 0x10; - SiS_Pr->CP_Vendor = panelvendor; - SiS_Pr->CP_Product = panelproduct; - } - - } - - if(paneltype && checkexpand) { - /* If any of the Established low-res modes is supported, the - * panel can scale automatically. For 800x600 panels, we only - * check the even lower ones. - */ - if(paneltype == Panel_800x600) { - if(buffer[0x23] & 0xfc) cr37 |= 0x10; - } else { - if(buffer[0x23]) cr37 |= 0x10; - } - } - - break; - - case 3: /* Analyze EDID V2 */ - case 4: - index = 0; - - if(!(checkedid2(buffer))) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "LCD sense: EDID corrupt\n"); - return 0; - } - - if((buffer[0x41] & 0x0f) == 0x03) { - index = 0x42 + 3; - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "LCD sense: Display supports TMDS input on primary interface\n"); - } else if((buffer[0x41] & 0xf0) == 0x30) { - index = 0x46 + 3; - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "LCD sense: Display supports TMDS input on secondary interface\n"); - } else { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "LCD sense: Display does not support TMDS video interface (0x%02x)\n", - buffer[0x41]); - return 0; - } - - SiS_Pr->CP_Vendor = panelvendor = buffer[2] | (buffer[1] << 8); - SiS_Pr->CP_Product = panelproduct = buffer[3] | (buffer[4] << 8); - - paneltype = Panel_Custom; - SiS_Pr->CP_MaxX = SiS_Pr->CP_PreferredX = xres = buffer[0x76] | (buffer[0x77] << 8); - SiS_Pr->CP_MaxY = SiS_Pr->CP_PreferredY = yres = buffer[0x78] | (buffer[0x79] << 8); - - switch(xres) { -#if 0 - case 800: - if(yres == 600) { - paneltype = Panel_800x600; - checkexpand = TRUE; - } - break; -#endif - case 1024: - if(yres == 768) { - paneltype = Panel_1024x768; - checkexpand = TRUE; - } - break; - case 1280: - if(yres == 960) { - if(pSiS->VGAEngine == SIS_315_VGA) { - paneltype = Panel310_1280x960; - } else { - paneltype = Panel300_1280x960; - } - } else if(yres == 1024) { - paneltype = Panel_1280x1024; - checkexpand = TRUE; - } - /* 1280x768 treated as custom here */ - break; - case 1400: - if(pSiS->VGAEngine == SIS_315_VGA) { - if(yres == 1050) { - paneltype = Panel310_1400x1050; - checkexpand = TRUE; - } - } - break; - case 1600: - if(pSiS->VGAEngine == SIS_315_VGA) { - if(pSiS->VBFlags & VB_301C) { - if(yres == 1200) { - paneltype = Panel310_1600x1200; - checkexpand = TRUE; - } - } - } - break; - } - - /* Determine if RGB18 or RGB24 */ - if(index) { - if((buffer[index] == 0x20) || (buffer[index] == 0x34)) { - cr37 |= 0x01; - } - } - - if(checkexpand) { - /* TODO - for now, we let the panel scale */ - cr37 |= 0x10; - } - - /* Now seek 4-Byte Timing codes and extract sync pol info */ - index = 0x80; - if(buffer[0x7e] & 0x20) { /* skip Luminance Table (if provided) */ - lumsize = buffer[0x80] & 0x1f; - if(buffer[0x80] & 0x80) lumsize *= 3; - lumsize++; /* luminance header byte */ - index += lumsize; - } -#if 0 /* "pixel rate" = pixel clock? */ - if(buffer[0x7e] & 0x1c) { - for(i=0; i<((buffer[0x7e] & 0x1c) >> 2); i++) { - if(buffer[index + (i*8) + 6] && (buffer[index + (i*8) + 7] & 0x0f)) { - int clk = (buffer[index + (i*8) + 6] | ((buffer[index + (i*8) + 7] & 0x0f) << 4)) * 1000; - if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk; - } - } - } -#endif - index += (((buffer[0x7e] & 0x1c) >> 2) * 8); /* skip Frequency Ranges */ - if(buffer[0x7e] & 0x03) { - for(i=0; i<(buffer[0x7e] & 0x03); i++) { - if((buffer[index + (i*27) + 9]) || (buffer[index + (i*27) + 10])) { - int clk = ((buffer[index + (i*27) + 9]) | ((buffer[index + (i*27) + 9]) << 8)) * 10; - if(clk > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = clk; - } - } - } - index += ((buffer[0x7e] & 0x03) * 27); /* skip Detailed Range Limits */ - numcodes = (buffer[0x7f] & 0xf8) >> 3; - if(numcodes) { - myindex = index; - seekcode = (xres - 256) / 16; - for(i=0; i<numcodes; i++) { - if(buffer[myindex] == seekcode) break; - myindex += 4; - } - if(buffer[myindex] == seekcode) { - cr37 |= ((((buffer[myindex + 1] & 0x0c) ^ 0x0c) << 4) | 0x20); - havesync = TRUE; - } else { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING, - "LCD sense: Unable to retrieve Sync polarity information\n"); - } - } else { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_WARNING, - "LCD sense: Unable to retrieve Sync polarity information\n"); - } - - /* Check against our database; Eg. Sanyo projector reports - * 1024x768 in non-HDPC mode, although it supports 1280x720. - * Treat such wrongly reporting panels as custom. - */ - if(paneltype != Panel_Custom) { - int maxx, maxy, prefx, prefy; - if((SiS_FindPanelFromDB(pSiS, panelvendor, panelproduct, &maxx, &maxy, &prefx, &prefy))) { - paneltype = Panel_Custom; - SiS_Pr->CP_MaxX = maxx; - SiS_Pr->CP_MaxY = maxy; - cr37 |= 0x10; - /* Leave preferred unchanged (MUST be a valid mode!) */ - } - } - - /* Now seek the detailed timing descriptions for custom panels */ - if(paneltype == Panel_Custom) { - - SiS_Pr->CP_Supports64048075 = TRUE; - - index += (numcodes * 4); - numcodes = buffer[0x7f] & 0x07; - for(i=0; i<numcodes; i++, index += 18) { - xres = buffer[index+2] | ((buffer[index+4] & 0xf0) << 4); - yres = buffer[index+5] | ((buffer[index+7] & 0xf0) << 4); - - SiS_Pr->CP_HDisplay[i] = xres; - SiS_Pr->CP_HSyncStart[i] = xres + (buffer[index+8] | ((buffer[index+11] & 0xc0) << 2)); - SiS_Pr->CP_HSyncEnd[i] = SiS_Pr->CP_HSyncStart[i] + (buffer[index+9] | ((buffer[index+11] & 0x30) << 4)); - SiS_Pr->CP_HTotal[i] = xres + (buffer[index+3] | ((buffer[index+4] & 0x0f) << 8)); - SiS_Pr->CP_HBlankStart[i] = xres + 1; - SiS_Pr->CP_HBlankEnd[i] = SiS_Pr->CP_HTotal[i]; - - SiS_Pr->CP_VDisplay[i] = yres; - SiS_Pr->CP_VSyncStart[i] = yres + (((buffer[index+10] & 0xf0) >> 4) | ((buffer[index+11] & 0x0c) << 2)); - SiS_Pr->CP_VSyncEnd[i] = SiS_Pr->CP_VSyncStart[i] + ((buffer[index+10] & 0x0f) | ((buffer[index+11] & 0x03) << 4)); - SiS_Pr->CP_VTotal[i] = yres + (buffer[index+6] | ((buffer[index+7] & 0x0f) << 8)); - SiS_Pr->CP_VBlankStart[i] = yres + 1; - SiS_Pr->CP_VBlankEnd[i] = SiS_Pr->CP_VTotal[i]; - - SiS_Pr->CP_Clock[i] = (buffer[index] | (buffer[index+1] << 8)) * 10; - - SiS_Pr->CP_DataValid[i] = TRUE; - - if((SiS_Pr->CP_HDisplay[i] & 7) || - (SiS_Pr->CP_HDisplay[i] > SiS_Pr->CP_HSyncStart[i]) || - (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HSyncEnd[i]) || - (SiS_Pr->CP_HDisplay[i] >= SiS_Pr->CP_HTotal[i]) || - (SiS_Pr->CP_HSyncStart[i] >= SiS_Pr->CP_HSyncEnd[i]) || - (SiS_Pr->CP_HSyncStart[i] > SiS_Pr->CP_HTotal[i]) || - (SiS_Pr->CP_HSyncEnd[i] > SiS_Pr->CP_HTotal[i]) || - (SiS_Pr->CP_VDisplay[i] > SiS_Pr->CP_VSyncStart[i]) || - (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VSyncEnd[i]) || - (SiS_Pr->CP_VDisplay[i] >= SiS_Pr->CP_VTotal[i]) || - (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VSyncEnd[i]) || - (SiS_Pr->CP_VSyncStart[i] > SiS_Pr->CP_VTotal[i]) || - (SiS_Pr->CP_VSyncEnd[i] > SiS_Pr->CP_VTotal[i]) || - (((pSiS->VBFlags & VB_301C) && (SiS_Pr->CP_Clock[i] > 162500)) || - ((!(pSiS->VBFlags & VB_301C)) && - ((SiS_Pr->CP_Clock[i] > 108200) || (SiS_Pr->CP_VDisplay[i] > 1024)))) || - (buffer[index + 17] & 0x80)) { - - SiS_Pr->CP_DataValid[i] = FALSE; - - } else { - - SiS_Pr->CP_HaveCustomData = TRUE; - - if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i]; - - if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) { - SiS_Pr->CP_PreferredIndex = i; - SiS_MakeClockRegs(pSiS->pScrn, SiS_Pr->CP_Clock[i], &SiS_Pr->CP_PrefSR2B, &SiS_Pr->CP_PrefSR2C); - SiS_Pr->CP_PrefClock = (SiS_Pr->CP_Clock[i] / 1000) + 1; - if(!havesync) { - cr37 |= ((((buffer[index + 17] & 0x06) ^ 0x06) << 5) | 0x20); - havesync = TRUE; - } - } - - SiS_Pr->CP_HSync_P[i] = (buffer[index + 17] & 0x02) ? TRUE : FALSE; - SiS_Pr->CP_VSync_P[i] = (buffer[index + 17] & 0x04) ? TRUE : FALSE; - SiS_Pr->CP_SyncValid[i] = TRUE; - - } - } - - cr37 |= 0x10; - - } - - break; - - } - - /* 1280x960 panels are always RGB24, unable to scale and use - * high active sync polarity - */ - if(pSiS->VGAEngine == SIS_315_VGA) { - if(paneltype == Panel310_1280x960) cr37 &= 0x0e; - } else { - if(paneltype == Panel300_1280x960) cr37 &= 0x0e; - } - - for(i = 0; i < 7; i++) { - if(SiS_Pr->CP_DataValid[i]) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "Non-standard LCD/DVI-D timing data no. %d:\n", i); - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - " HDisplay %d HSync %d HSyncEnd %d HTotal %d\n", - SiS_Pr->CP_HDisplay[i], SiS_Pr->CP_HSyncStart[i], - SiS_Pr->CP_HSyncEnd[i], SiS_Pr->CP_HTotal[i]); - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - " VDisplay %d VSync %d VSyncEnd %d VTotal %d\n", - SiS_Pr->CP_VDisplay[i], SiS_Pr->CP_VSyncStart[i], - SiS_Pr->CP_VSyncEnd[i], SiS_Pr->CP_VTotal[i]); - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - " Pixel clock: %3.3fMhz\n", (float)SiS_Pr->CP_Clock[i] / 1000); - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_INFO, - " To use this, add \"%dx%d\" to the list of Modes in the Screen section\n", - SiS_Pr->CP_HDisplay[i], - SiS_Pr->CP_VDisplay[i]); - } - } - - if(paneltype) { - if(!SiS_Pr->CP_PreferredX) SiS_Pr->CP_PreferredX = SiS_Pr->CP_MaxX; - if(!SiS_Pr->CP_PreferredY) SiS_Pr->CP_PreferredY = SiS_Pr->CP_MaxY; - SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x08); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,paneltype); - cr37 &= 0xf1; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0x0c,cr37); - SiS_Pr->PanelSelfDetected = TRUE; -#ifdef TWDEBUG - xf86DrvMsgVerb(pSiS->pScrn->scrnIndex, X_PROBED, 3, - "LCD sense: [DDC LCD results: 0x%02x, 0x%02x]\n", paneltype, cr37); -#endif - } else { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x32,~0x08); - SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,0x00); - } - return 0; -} - -USHORT -SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SISPtr pSiS) -{ - USHORT DDCdatatype,flag; - BOOLEAN foundcrt = FALSE; - int retry; - unsigned char buffer[256]; - - if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0; - - if(SiS_InitDDCRegs(SiS_Pr, pSiS->VBFlags, pSiS->VGAEngine, 2, 0, FALSE) == 0xFFFF) return 0; - - SiS_Pr->SiS_DDC_SecAddr = 0x00; - - /* Probe supported DA's */ - flag = SiS_ProbeDDC(SiS_Pr); - if(flag & 0x10) { - SiS_Pr->SiS_DDC_DeviceAddr = 0xa6; /* EDID V2 (FP) */ - DDCdatatype = 4; - } else if(flag & 0x08) { - SiS_Pr->SiS_DDC_DeviceAddr = 0xa2; /* EDID V2 (P&D-D Monitor) */ - DDCdatatype = 3; - } else if(flag & 0x02) { - SiS_Pr->SiS_DDC_DeviceAddr = 0xa0; /* EDID V1 */ - DDCdatatype = 1; - } else { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "VGA2 sense: Do DDC answer\n"); - return 0; /* no DDC support (or no device attached) */ - } - - /* Read the entire EDID */ - retry = 2; - do { - if(SiS_ReadDDC(SiS_Pr, DDCdatatype, buffer)) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_PROBED, - "VGA2 sense: DDC read failed (attempt %d), %s\n", - (3-retry), (retry == 1) ? "giving up" : "retrying"); - retry--; - if(retry == 0) return 0xFFFF; - } else break; - } while(1); - - /* Analyze EDID. We don't have many chances to - * distinguish a flat panel from a CRT... - */ - switch(DDCdatatype) { - case 1: - if(!(checkedid1(buffer))) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR, - "VGA2 sense: EDID corrupt\n"); - return 0; - } - if(buffer[0x14] & 0x80) { /* Display uses digital input */ - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR, - "VGA2 sense: Attached display expects digital input\n"); - return 0; - } - SiS_Pr->CP_Vendor = buffer[9] | (buffer[8] << 8); - SiS_Pr->CP_Product = buffer[10] | (buffer[11] << 8); - foundcrt = TRUE; - break; - case 3: - case 4: - if(!(checkedid2(buffer))) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR, - "VGA2 sense: EDID corrupt\n"); - return 0; - } - if( ((buffer[0x41] & 0x0f) != 0x01) && /* Display does not support analog input */ - ((buffer[0x41] & 0x0f) != 0x02) && - ((buffer[0x41] & 0xf0) != 0x10) && - ((buffer[0x41] & 0xf0) != 0x20) ) { - xf86DrvMsg(pSiS->pScrn->scrnIndex, X_ERROR, - "VGA2 sense: Attached display does not support analog input (0x%02x)\n", - buffer[0x41]); - return 0; - } - SiS_Pr->CP_Vendor = buffer[2] | (buffer[1] << 8); - SiS_Pr->CP_Product = buffer[3] | (buffer[4] << 8); - foundcrt = TRUE; - break; - } - - if(foundcrt) { - SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x10); - } - return(0); -} - -#endif - -void -SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh) -{ - USHORT tempbl; - - tempbl = SiS_GetCH70xx(SiS_Pr,(tempax & 0x00FF)); - tempbl = (((tempbl & tempbh) << 8) | tempax); - SiS_SetCH70xx(SiS_Pr,tempbl); -} - /* Generic I2C functions for Chrontel & DDC --------- */ static void -SiS_SetSwitchDDC2(SiS_Private *SiS_Pr) +SiS_SetSwitchDDC2(struct SiS_Private *SiS_Pr) { SiS_SetSCLKHigh(SiS_Pr); SiS_WaitRetrace1(SiS_Pr); @@ -10505,124 +9502,126 @@ SiS_SetSwitchDDC2(SiS_Private *SiS_Pr) SiS_WaitRetrace1(SiS_Pr); } -USHORT -SiS_ReadDDC1Bit(SiS_Private *SiS_Pr) +unsigned short +SiS_ReadDDC1Bit(struct SiS_Private *SiS_Pr) { SiS_WaitRetrace1(SiS_Pr); - return((SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x02) >> 1); + return ((SiS_GetReg(SiS_Pr->SiS_P3c4,0x11) & 0x02) >> 1); } /* Set I2C start condition */ /* This is done by a SD high-to-low transition while SC is high */ -static USHORT -SiS_SetStart(SiS_Private *SiS_Pr) +static unsigned short +SiS_SetStart(struct SiS_Private *SiS_Pr) { - if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF; /* (SC->low) */ + if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF; /* (SC->low) */ SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NData, - SiS_Pr->SiS_DDC_Data); /* SD->high */ - if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* SC->high */ + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* SD->high */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* SC->high */ SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NData, - 0x00); /* SD->low = start condition */ - if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* (SC->low) */ + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* SD->low = start condition */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* (SC->low) */ return 0; } /* Set I2C stop condition */ /* This is done by a SD low-to-high transition while SC is high */ -static USHORT -SiS_SetStop(SiS_Private *SiS_Pr) +static unsigned short +SiS_SetStop(struct SiS_Private *SiS_Pr) { - if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF; /* (SC->low) */ + if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF; /* (SC->low) */ SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NData, - 0x00); /* SD->low */ - if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* SC->high */ + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* SD->low */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* SC->high */ SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NData, - SiS_Pr->SiS_DDC_Data); /* SD->high = stop condition */ - if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* (SC->high) */ + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* SD->high = stop condition */ + if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* (SC->high) */ return 0; } /* Write 8 bits of data */ -static USHORT -SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax) +static unsigned short +SiS_WriteDDC2Data(struct SiS_Private *SiS_Pr, unsigned short tempax) { - USHORT i,flag,temp; + unsigned short i,flag,temp; flag = 0x80; - for(i=0; i<8; i++) { - SiS_SetSCLKLow(SiS_Pr); /* SC->low */ + for(i = 0; i < 8; i++) { + SiS_SetSCLKLow(SiS_Pr); /* SC->low */ if(tempax & flag) { SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NData, - SiS_Pr->SiS_DDC_Data); /* Write bit (1) to SD */ + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* Write bit (1) to SD */ } else { SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NData, - 0x00); /* Write bit (0) to SD */ + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* Write bit (0) to SD */ } - SiS_SetSCLKHigh(SiS_Pr); /* SC->high */ + SiS_SetSCLKHigh(SiS_Pr); /* SC->high */ flag >>= 1; } - temp = SiS_CheckACK(SiS_Pr); /* Check acknowledge */ - return(temp); + temp = SiS_CheckACK(SiS_Pr); /* Check acknowledge */ + return temp; } -static USHORT -SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax) +static unsigned short +SiS_ReadDDC2Data(struct SiS_Private *SiS_Pr) { - USHORT i,temp,getdata; + unsigned short i, temp, getdata; - getdata=0; - for(i=0; i<8; i++) { + getdata = 0; + for(i = 0; i < 8; i++) { getdata <<= 1; SiS_SetSCLKLow(SiS_Pr); SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, SiS_Pr->SiS_DDC_Data); SiS_SetSCLKHigh(SiS_Pr); temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); if(temp & SiS_Pr->SiS_DDC_Data) getdata |= 0x01; } - return(getdata); + return getdata; } -static USHORT -SiS_SetSCLKLow(SiS_Private *SiS_Pr) +static unsigned short +SiS_SetSCLKLow(struct SiS_Private *SiS_Pr) { SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NClk, - 0x00); /* SetSCLKLow() */ + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NClk, + 0x00); /* SetSCLKLow() */ SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); return 0; } -static USHORT -SiS_SetSCLKHigh(SiS_Private *SiS_Pr) +static unsigned short +SiS_SetSCLKHigh(struct SiS_Private *SiS_Pr) { - USHORT temp, watchdog=1000; + unsigned short temp, watchdog=1000; SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NClk, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NClk, SiS_Pr->SiS_DDC_Clk); /* SetSCLKHigh() */ do { temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); } while((!(temp & SiS_Pr->SiS_DDC_Clk)) && --watchdog); if (!watchdog) { +#ifdef SIS_XORG_XF86 #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "SetClkHigh failed\n"); +#endif #endif return 0xFFFF; } @@ -10632,21 +9631,21 @@ SiS_SetSCLKHigh(SiS_Private *SiS_Pr) /* Check I2C acknowledge */ /* Returns 0 if ack ok, non-0 if ack not ok */ -static USHORT -SiS_CheckACK(SiS_Private *SiS_Pr) +static unsigned short +SiS_CheckACK(struct SiS_Private *SiS_Pr) { - USHORT tempah; + unsigned short tempah; SiS_SetSCLKLow(SiS_Pr); /* (SC->low) */ SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, - SiS_Pr->SiS_DDC_Index, - SiS_Pr->SiS_DDC_NData, - SiS_Pr->SiS_DDC_Data); /* (SD->high) */ + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* (SD->high) */ SiS_SetSCLKHigh(SiS_Pr); /* SC->high = clock impulse for ack */ tempah = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); /* Read SD */ SiS_SetSCLKLow(SiS_Pr); /* SC->low = end of clock impulse */ - if(tempah & SiS_Pr->SiS_DDC_Data) return(1); /* Ack OK if bit = 0 */ - else return(0); + if(tempah & SiS_Pr->SiS_DDC_Data) return 1; /* Ack OK if bit = 0 */ + return 0; } /* End of I2C functions ----------------------- */ @@ -10656,67 +9655,67 @@ SiS_CheckACK(SiS_Private *SiS_Pr) #ifdef SIS315H -static USHORT -GetRAMDACromptr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +static unsigned short +GetRAMDACromptr(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT romptr; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr; - if(HwInfo->jChipType < SIS_330) { + if(SiS_Pr->ChipType < SIS_330) { romptr = SISGETROMW(0x128); - if(SiS_Pr->SiS_VBType & VB_SIS301B302B) + if(SiS_Pr->SiS_VBType & VB_SIS30xB) romptr = SISGETROMW(0x12a); } else { romptr = SISGETROMW(0x1a8); - if(SiS_Pr->SiS_VBType & VB_SIS301B302B) + if(SiS_Pr->SiS_VBType & VB_SIS30xB) romptr = SISGETROMW(0x1aa); } - return(romptr); + return romptr; } -static USHORT -GetLCDromptr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +static unsigned short +GetLCDromptr(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT romptr; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr; - if(HwInfo->jChipType < SIS_330) { + if(SiS_Pr->ChipType < SIS_330) { romptr = SISGETROMW(0x120); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) romptr = SISGETROMW(0x122); } else { romptr = SISGETROMW(0x1a0); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) romptr = SISGETROMW(0x1a2); } - return(romptr); + return romptr; } -static USHORT -GetTVromptr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +static unsigned short +GetTVromptr(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT romptr; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr; - if(HwInfo->jChipType < SIS_330) { + if(SiS_Pr->ChipType < SIS_330) { romptr = SISGETROMW(0x114); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) romptr = SISGETROMW(0x11a); } else { romptr = SISGETROMW(0x194); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) romptr = SISGETROMW(0x19a); } - return(romptr); + return romptr; } -static USHORT -GetLCDPtrIndexBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +static unsigned short +GetLCDPtrIndexBIOS(struct SiS_Private *SiS_Pr) { - USHORT index; + unsigned short index; - if((IS_SIS650) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { - if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) { + if((IS_SIS650) && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { + if(!(SiS_IsNotM650orLater(SiS_Pr))) { if((index = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xf0)) { index >>= 4; index *= 3; @@ -10729,7 +9728,12 @@ GetLCDPtrIndexBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) index = SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F; if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) index -= 5; - else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) index -= 6; + if(SiS_Pr->SiS_VBType & VB_SIS301C) { /* 1.15.20 and later (not VB specific) */ + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) index -= 5; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768) index -= 5; + } else { + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) index -= 6; + } index--; index *= 3; if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; @@ -10737,10 +9741,10 @@ GetLCDPtrIndexBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) return index; } -static USHORT -GetLCDPtrIndex(SiS_Private *SiS_Pr) +static unsigned short +GetLCDPtrIndex(struct SiS_Private *SiS_Pr) { - USHORT index; + unsigned short index; index = ((SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F) - 1) * 3; if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; @@ -10748,10 +9752,10 @@ GetLCDPtrIndex(SiS_Private *SiS_Pr) return index; } -static USHORT -GetTVPtrIndex(SiS_Private *SiS_Pr) +static unsigned short +GetTVPtrIndex(struct SiS_Private *SiS_Pr) { - USHORT index; + unsigned short index; index = 0; if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 1; @@ -10769,10 +9773,10 @@ GetTVPtrIndex(SiS_Private *SiS_Pr) return index; } -static ULONG -GetOEMTVPtr661_2_GEN(SiS_Private *SiS_Pr, int addme) +static unsigned int +GetOEMTVPtr661_2_GEN(struct SiS_Private *SiS_Pr, int addme) { - USHORT index = 0, temp = 0; + unsigned short index = 0, temp = 0; if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 1; if(SiS_Pr->SiS_TVMode & TVSetPALM) index = 2; @@ -10784,7 +9788,7 @@ GetOEMTVPtr661_2_GEN(SiS_Private *SiS_Pr, int addme) if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) index = 7; } - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) { index += addme; @@ -10792,25 +9796,25 @@ GetOEMTVPtr661_2_GEN(SiS_Private *SiS_Pr, int addme) } temp += 0x0100; } - return(ULONG)(index | (temp << 16)); + return (unsigned int)(index | (temp << 16)); } -static ULONG -GetOEMTVPtr661_2_OLD(SiS_Private *SiS_Pr) +static unsigned int +GetOEMTVPtr661_2_OLD(struct SiS_Private *SiS_Pr) { - return(GetOEMTVPtr661_2_GEN(SiS_Pr, 8)); + return (GetOEMTVPtr661_2_GEN(SiS_Pr, 8)); } #if 0 -static ULONG -GetOEMTVPtr661_2_NEW(SiS_Private *SiS_Pr) +static unsigned int +GetOEMTVPtr661_2_NEW(struct SiS_Private *SiS_Pr) { - return(GetOEMTVPtr661_2_GEN(SiS_Pr, 6)); + return (GetOEMTVPtr661_2_GEN(SiS_Pr, 6)); } #endif static int -GetOEMTVPtr661(SiS_Private *SiS_Pr) +GetOEMTVPtr661(struct SiS_Private *SiS_Pr) { int index = 0; @@ -10833,10 +9837,10 @@ GetOEMTVPtr661(SiS_Private *SiS_Pr) } static void -SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) +SetDelayComp(struct SiS_Private *SiS_Pr, unsigned short ModeNo) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT delay=0,index,myindex,temp,romptr=0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short delay=0,index,myindex,temp,romptr=0; BOOLEAN dochiptest = TRUE; if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { @@ -10848,19 +9852,19 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) /* Find delay (from ROM, internal tables, PCI subsystem) */ if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { /* ------------ VGA */ - + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { - romptr = GetRAMDACromptr(SiS_Pr, HwInfo); + romptr = GetRAMDACromptr(SiS_Pr); } if(romptr) delay = ROMAddr[romptr]; else { delay = 0x04; - if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + if(SiS_Pr->SiS_VBType & VB_SIS30xB) { if(IS_SIS650) { delay = 0x0a; } else if(IS_SIS740) { delay = 0x00; - } else if(HwInfo->jChipType < SIS_330) { + } else if(SiS_Pr->ChipType < SIS_330) { delay = 0x0c; } else { delay = 0x0c; @@ -10901,8 +9905,12 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,delay); } else { delay = 0x0c; - if(SiS_Pr->SiS_VBType & VB_SIS301C) delay = 0x03; - else if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_Pr->SiS_VBType & VB_SIS301C) { + delay = 0x03; + if((SiS_Pr->PanelXRes > 1280) && (SiS_Pr->PanelYRes > 1024)) { + delay = 0x00; + } + } else if(SiS_Pr->SiS_VBType & VB_SISLVDS) { if(IS_SIS740) delay = 0x01; else delay = 0x03; } @@ -10947,12 +9955,12 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) if(!gotitfrompci) { - index = GetLCDPtrIndexBIOS(SiS_Pr, HwInfo); + index = GetLCDPtrIndexBIOS(SiS_Pr); myindex = GetLCDPtrIndex(SiS_Pr); - if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { + if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { - if(SiS_IsNotM650orLater(SiS_Pr, HwInfo)) { + if(SiS_IsNotM650orLater(SiS_Pr)) { if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { /* Always use the second pointer on 650; some BIOSes */ @@ -10978,11 +9986,12 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) (!(SiS_Pr->SiS_ROMNew)) && (SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) && (SiS_Pr->SiS_LCDResInfo != Panel_1280x768) && - (SiS_Pr->SiS_LCDResInfo != Panel_1280x960)) { + (SiS_Pr->SiS_LCDResInfo != Panel_1280x960) && + (SiS_Pr->SiS_LCDResInfo != Panel_1600x1200) && + ((romptr = GetLCDromptr(SiS_Pr)))) { /* Data for 1280x1024 wrong in 301B BIOS */ - romptr = GetLCDromptr(SiS_Pr, HwInfo); - if(!romptr) return; + /* Data for 1600x1200 wrong in 301C BIOS */ delay = ROMAddr[(romptr + index)]; } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { @@ -10993,14 +10002,15 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) } else { delay = SiS310_LCDDelayCompensation_301[myindex]; - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { if(IS_SIS740) delay = 0x01; - else if(HwInfo->jChipType <= SIS_315PRO) delay = SiS310_LCDDelayCompensation_3xx301LV[myindex]; + else if(SiS_Pr->ChipType <= SIS_315PRO) delay = SiS310_LCDDelayCompensation_3xx301LV[myindex]; else delay = SiS310_LCDDelayCompensation_650301LV[myindex]; } else if(SiS_Pr->SiS_VBType & VB_SIS301C) { if(IS_SIS740) delay = 0x01; /* ? */ else delay = 0x03; - } else if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) delay = 0x00; /* experience */ + } else if(SiS_Pr->SiS_VBType & VB_SIS30xB) { if(IS_SIS740) delay = 0x01; else delay = SiS310_LCDDelayCompensation_3xx301B[myindex]; } @@ -11013,14 +10023,14 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0x0F,((delay << 4) & 0xf0)); dochiptest = FALSE; } - + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* ------------ TV */ index = GetTVPtrIndex(SiS_Pr); - - if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { - if(SiS_IsNotM650orLater(SiS_Pr,HwInfo)) { + if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { + + if(SiS_IsNotM650orLater(SiS_Pr)) { if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { /* Always use the second pointer on 650; some BIOSes */ @@ -11062,7 +10072,7 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) } else if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { - romptr = GetTVromptr(SiS_Pr, HwInfo); + romptr = GetTVromptr(SiS_Pr); if(!romptr) return; delay = ROMAddr[romptr + index]; @@ -11073,7 +10083,7 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) } else { delay = SiS310_TVDelayCompensation_301[index]; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { if(IS_SIS740) { delay = SiS310_TVDelayCompensation_740301B[index]; /* LV: use 301 data? BIOS bug? */ @@ -11085,18 +10095,18 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) } - if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) { + if(SiS_LCDAEnabled(SiS_Pr)) { delay &= 0x0f; dochiptest = FALSE; } - + } else return; /* Write delay */ if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && dochiptest) { + if(IS_SIS650 && (SiS_Pr->SiS_VBType & VB_SISLVDS) && dochiptest) { temp = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xf0) >> 4; if(temp == 8) { /* 1400x1050 BIOS (COMPAL) */ @@ -11134,11 +10144,10 @@ SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) } static void -SetAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex) +SetAntiFlicker(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index,temp,temp1,romptr=0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,temp1,romptr=0; if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p|TVSetYPbPr525p)) return; @@ -11152,14 +10161,14 @@ SetAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, temp1 = temp; if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { - if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->ChipType >= SIS_661) { temp1 = GetOEMTVPtr661(SiS_Pr); temp1 >>= 1; romptr = SISGETROMW(0x260); - if(HwInfo->jChipType >= SIS_760) { + if(SiS_Pr->ChipType >= SIS_760) { romptr = SISGETROMW(0x360); } - } else if(HwInfo->jChipType >= SIS_330) { + } else if(SiS_Pr->ChipType >= SIS_330) { romptr = SISGETROMW(0x192); } else { romptr = SISGETROMW(0x112); @@ -11178,11 +10187,10 @@ SetAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } static void -SetEdgeEnhance(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex) +SetEdgeEnhance(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index,temp,temp1,romptr=0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,temp1,romptr=0; temp = temp1 = GetTVPtrIndex(SiS_Pr) >> 1; /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */ @@ -11192,14 +10200,14 @@ SetEdgeEnhance(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex; if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { - if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->ChipType >= SIS_661) { romptr = SISGETROMW(0x26c); - if(HwInfo->jChipType >= SIS_760) { + if(SiS_Pr->ChipType >= SIS_760) { romptr = SISGETROMW(0x36c); } temp1 = GetOEMTVPtr661(SiS_Pr); temp1 >>= 1; - } else if(HwInfo->jChipType >= SIS_330) { + } else if(SiS_Pr->ChipType >= SIS_330) { romptr = SISGETROMW(0x1a4); } else { romptr = SISGETROMW(0x124); @@ -11217,10 +10225,9 @@ SetEdgeEnhance(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } static void -SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex) +SetYFilter(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex) { - USHORT index, temp, i, j; + unsigned short index, temp, i, j; if(ModeNo <= 0x13) { index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex; @@ -11235,7 +10242,7 @@ SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, else if(SiS_Pr->SiS_TVMode & TVSetPALN) temp = 4; /* PAL-N */ if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) temp = 1; /* HiVision uses PAL */ - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { for(i=0x35, j=0; i<=0x38; i++, j++) { SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]); } @@ -11250,23 +10257,22 @@ SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } static void -SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex) +SetPhaseIncr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index,temp,i,j,resinfo,romptr=0; - ULONG lindex; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,i,j,resinfo,romptr=0; + unsigned int lindex; if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return; /* NTSC-J data not in BIOS, and already set in SetGroup2 */ if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) return; - if((HwInfo->jChipType >= SIS_661) || SiS_Pr->SiS_ROMNew) { + if((SiS_Pr->ChipType >= SIS_661) || SiS_Pr->SiS_ROMNew) { lindex = GetOEMTVPtr661_2_OLD(SiS_Pr) & 0xffff; lindex <<= 2; for(j=0, i=0x31; i<=0x34; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS661_TVPhase[lindex + j]); + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS_TVPhase[lindex + j]); } return; } @@ -11286,17 +10292,17 @@ SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, */ if(SiS_Pr->SiS_UseROM) { romptr = SISGETROMW(0x116); - if(HwInfo->jChipType >= SIS_330) { + if(SiS_Pr->ChipType >= SIS_330) { romptr = SISGETROMW(0x196); } - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { romptr = SISGETROMW(0x11c); - if(HwInfo->jChipType >= SIS_330) { + if(SiS_Pr->ChipType >= SIS_330) { romptr = SISGETROMW(0x19c); } if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && (!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode))) { romptr = SISGETROMW(0x116); - if(HwInfo->jChipType >= SIS_330) { + if(SiS_Pr->ChipType >= SIS_330) { romptr = SISGETROMW(0x196); } } @@ -11311,7 +10317,7 @@ SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, index = temp % 2; temp >>= 1; /* 0:NTSC, 1:PAL, 2:HiTV */ for(j=0, i=0x31; i<=0x34; i++, j++) { - if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) + if(!(SiS_Pr->SiS_VBType & VB_SIS30xBLV)) SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]); else if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr2[temp][index][j]); @@ -11320,7 +10326,7 @@ SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } } - if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision))) { + if((SiS_Pr->SiS_VBType & VB_SIS30xBLV) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision))) { if((!(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetYPbPr525p | TVSetYPbPr750p))) && (ModeNo > 0x13)) { if((resinfo == SIS_RI_640x480) || (resinfo == SIS_RI_800x600)) { @@ -11339,11 +10345,11 @@ SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } static void -SetDelayComp661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, - USHORT ModeIdIndex, USHORT RTI) +SetDelayComp661(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RTI) { - USHORT delay = 0, romptr = 0, index, lcdpdcindex; - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + unsigned short delay = 0, romptr = 0, index, lcdpdcindex; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA | SetCRT2ToRAMDAC))) return; @@ -11359,7 +10365,7 @@ SetDelayComp661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, if(SiS_Pr->UseCustomMode) { index = SiS_Pr->CSRClock; } else if(ModeNo > 0x13) { - index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RTI,HwInfo); + index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RTI); index = SiS_Pr->SiS_VCLKData[index].CLOCK; } if(index < 25) index = 25; @@ -11387,7 +10393,36 @@ SetDelayComp661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, else delay = (SiS_Pr->SiS_RefIndex[RTI].Ext_PDC >> 4); delay |= (delay << 8); - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + if(SiS_Pr->ChipType >= XGI_20) { + + delay = 0x0606; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + + delay = 0x0404; + if(SiS_Pr->SiS_XGIROM) { + index = GetTVPtrIndex(SiS_Pr); + if((romptr = SISGETROMW(0x35e))) { + delay = (ROMAddr[romptr + index] & 0x0f) << 1; + delay |= (delay << 8); + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(SiS_Pr->ChipType == XGI_40 && SiS_Pr->ChipRevision == 0x02) { + delay -= 0x0404; + } + } + } + + } else if(SiS_Pr->ChipType >= SIS_340) { + + delay = 0x0606; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + delay = 0x0404; + } + /* TODO (eventually) */ + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* 3. TV */ @@ -11406,7 +10441,7 @@ SetDelayComp661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, /* 4. LCD, LCDA (for new ROM only LV and non-Pass 1:1) */ if( (SiS_Pr->SiS_LCDResInfo != Panel_Custom) && - ((romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo))) ) { + ((romptr = GetLCDStructPtr661_2(SiS_Pr))) ) { lcdpdcindex = (SiS_Pr->SiS_VBType & VB_UMC) ? 14 : 12; @@ -11426,6 +10461,7 @@ SetDelayComp661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, case Panel_1280x768_2:delay = 0x0004; break; case Panel_1280x800: case Panel_1280x800_2:delay = 0x0004; break; /* Verified for 1280x800 */ + case Panel_1280x854: delay = 0x0004; break; /* FIXME */ case Panel_1280x1024: delay = 0x1e04; break; case Panel_1400x1050: delay = 0x0004; break; case Panel_1600x1200: delay = 0x0400; break; @@ -11469,10 +10505,10 @@ SetDelayComp661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, } static void -SetCRT2SyncDither661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT RTI) +SetCRT2SyncDither661(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short RTI) { - USHORT infoflag; - UCHAR temp; + unsigned short infoflag; + unsigned char temp; if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { @@ -11513,12 +10549,16 @@ SetCRT2SyncDither661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, US } static void -SetPanelParms661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SetPanelParms661(struct SiS_Private *SiS_Pr) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT romptr, temp1, temp2; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short romptr, temp1, temp2; + + if(SiS_Pr->SiS_VBType & (VB_SISLVDS | VB_SIS30xC)) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x24,0x0f); + } - if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { if(SiS_Pr->LVDSHL != -1) { SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,SiS_Pr->LVDSHL); } @@ -11526,8 +10566,8 @@ SetPanelParms661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) if(SiS_Pr->SiS_ROMNew) { - if((romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo))) { - if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) { + if((romptr = GetLCDStructPtr661_2(SiS_Pr))) { + if(SiS_Pr->SiS_VBType & VB_SISLVDS) { temp1 = (ROMAddr[romptr] & 0x03) | 0x0c; temp2 = 0xfc; if(SiS_Pr->LVDSHL != -1) { @@ -11546,48 +10586,47 @@ SetPanelParms661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) } static void -SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex,USHORT RRTI) +SiS_OEM310Setting(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RRTI) { if((SiS_Pr->SiS_ROMNew) && (SiS_Pr->SiS_VBType & VB_SISLVDS)) { - SetDelayComp661(SiS_Pr,HwInfo,ModeNo,ModeIdIndex,RRTI); + SetDelayComp661(SiS_Pr, ModeNo, ModeIdIndex, RRTI); if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - SetCRT2SyncDither661(SiS_Pr,HwInfo,ModeNo,RRTI); - SetPanelParms661(SiS_Pr,HwInfo); + SetCRT2SyncDither661(SiS_Pr, ModeNo, RRTI); + SetPanelParms661(SiS_Pr); } } else { - SetDelayComp(SiS_Pr,HwInfo,ModeNo); + SetDelayComp(SiS_Pr,ModeNo); } if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { - SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); - SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); - SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + SetAntiFlicker(SiS_Pr,ModeNo,ModeIdIndex); + SetPhaseIncr(SiS_Pr,ModeNo,ModeIdIndex); + SetYFilter(SiS_Pr,ModeNo,ModeIdIndex); if(SiS_Pr->SiS_VBType & VB_SIS301) { - SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + SetEdgeEnhance(SiS_Pr,ModeNo,ModeIdIndex); } } } static void -SiS_OEM661Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI) +SiS_OEM661Setting(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, unsigned short RRTI) { if(SiS_Pr->SiS_VBType & VB_SISVB) { - SetDelayComp661(SiS_Pr,HwInfo,ModeNo,ModeIdIndex,RRTI); + SetDelayComp661(SiS_Pr, ModeNo, ModeIdIndex, RRTI); if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - SetCRT2SyncDither661(SiS_Pr,HwInfo,ModeNo,RRTI); - SetPanelParms661(SiS_Pr,HwInfo); + SetCRT2SyncDither661(SiS_Pr, ModeNo, RRTI); + SetPanelParms661(SiS_Pr); } if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); - SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); - SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + SetPhaseIncr(SiS_Pr, ModeNo, ModeIdIndex); + SetYFilter(SiS_Pr, ModeNo, ModeIdIndex); + SetAntiFlicker(SiS_Pr, ModeNo, ModeIdIndex); if(SiS_Pr->SiS_VBType & VB_SIS301) { - SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + SetEdgeEnhance(SiS_Pr, ModeNo, ModeIdIndex); } } } @@ -11601,13 +10640,12 @@ SiS_OEM661Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, * pray that we have a backup... */ static void -SiS_FinalizeLCD(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo) +SiS_FinalizeLCD(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - USHORT tempcl,tempch,tempbl,tempbh,tempbx,tempax,temp; - USHORT resinfo,modeflag; + unsigned short tempcl,tempch,tempbl,tempbh,tempbx,tempax,temp; + unsigned short resinfo,modeflag; - if(!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) return; + if(!(SiS_Pr->SiS_VBType & VB_SISLVDS)) return; if(SiS_Pr->SiS_ROMNew) return; if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { @@ -11678,7 +10716,7 @@ SiS_FinalizeLCD(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if(SiS_Pr->SiS_VBType & VB_SISEMI) { SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); #ifdef SET_EMI SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); @@ -11806,11 +10844,11 @@ SiS_FinalizeLCD(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, #ifdef SIS300 static void -SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex, USHORT RefTabIndex) +SetOEMLCDData2(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex, + unsigned short RefTabIndex) { - USHORT crt2crtc=0, modeflag, myindex=0; - UCHAR temp; + unsigned short crt2crtc=0, modeflag, myindex=0; + unsigned char temp; int i; if(ModeNo <= 0x13) { @@ -11849,21 +10887,21 @@ SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } } -static USHORT -GetOEMLCDPtr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, int Flag) +static unsigned short +GetOEMLCDPtr(struct SiS_Private *SiS_Pr, int Flag) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT tempbx=0,romptr=0; - UCHAR customtable300[] = { - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short tempbx=0,romptr=0; + static const unsigned char customtable300[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; - UCHAR customtable630[] = { - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + static const unsigned char customtable630[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; - if(HwInfo->jChipType == SIS_300) { + if(SiS_Pr->ChipType == SIS_300) { tempbx = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0x0f; if(SiS_Pr->SiS_VBType & VB_SIS301) tempbx &= 0x07; @@ -11912,11 +10950,10 @@ GetOEMLCDPtr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, int Flag) } static void -SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex) +SetOEMLCDDelay(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index,temp,romptr=0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,romptr=0; if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return; @@ -11927,22 +10964,22 @@ SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } /* The Panel Compensation Delay should be set according to tables - * here. Unfortunately, various BIOS versions don't case about + * here. Unfortunately, various BIOS versions don't care about * a uniform way using eg. ROM byte 0x220, but use different * hard coded delays (0x04, 0x20, 0x18) in SetGroup1(). - * Thus we don't set this if the user select a custom pdc or if + * Thus we don't set this if the user selected a custom pdc or if * we otherwise detected a valid pdc. */ if(SiS_Pr->PDC != -1) return; - temp = GetOEMLCDPtr(SiS_Pr,HwInfo, 0); + temp = GetOEMLCDPtr(SiS_Pr, 0); if(SiS_Pr->UseCustomMode) index = 0; else index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex; - if(HwInfo->jChipType != SIS_300) { + if(SiS_Pr->ChipType != SIS_300) { if(romptr) { romptr += (temp * 2); romptr = SISGETROMW(romptr); @@ -11986,12 +11023,11 @@ SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } static void -SetOEMLCDData(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex) +SetOEMLCDData(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { #if 0 /* Unfinished; Data table missing */ - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index,temp; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp; if((SiS_Pr->SiS_UseROM) { if(!(ROMAddr[0x237] & 0x01)) return; @@ -11999,8 +11035,8 @@ SetOEMLCDData(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, /* No rom pointer in BIOS header! */ } - temp = GetOEMLCDPtr(SiS_Pr,HwInfo, 1); - if(temp = 0xFFFF) return; + temp = GetOEMLCDPtr(SiS_Pr, 1); + if(temp == 0xFFFF) return; index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex]._VB_LCDHIndex; for(i=0x14, j=0; i<=0x17; i++, j++) { @@ -12018,10 +11054,10 @@ SetOEMLCDData(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, #endif } -static USHORT -GetOEMTVPtr(SiS_Private *SiS_Pr) +static unsigned short +GetOEMTVPtr(struct SiS_Private *SiS_Pr) { - USHORT index; + unsigned short index; index = 0; if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) index += 4; @@ -12037,11 +11073,10 @@ GetOEMTVPtr(SiS_Private *SiS_Pr) } static void -SetOEMTVDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex) +SetOEMTVDelay(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index,temp,romptr=0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,romptr=0; if(SiS_Pr->SiS_UseROM) { if(!(ROMAddr[0x238] & 0x01)) return; @@ -12070,11 +11105,10 @@ SetOEMTVDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } static void -SetOEMAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo, USHORT ModeIdIndex) +SetOEMAntiFlicker(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index,temp,romptr=0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,romptr=0; if(SiS_Pr->SiS_UseROM) { if(!(ROMAddr[0x238] & 0x01)) return; @@ -12099,11 +11133,10 @@ SetOEMAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } static void -SetOEMPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex) +SetOEMPhaseIncr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,unsigned short ModeIdIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index,i,j,temp,romptr=0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,i,j,temp,romptr=0; if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) return; @@ -12119,7 +11152,7 @@ SetOEMPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVPhaseIndex; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { for(i=0x31, j=0; i<=0x34; i++, j++) { SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Phase2[temp][index][j]); } @@ -12140,11 +11173,10 @@ SetOEMPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } static void -SetOEMYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex) +SetOEMYFilter(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index,temp,i,j,romptr=0; + unsigned char *ROMAddr = SiS_Pr->VirtualRomBase; + unsigned short index,temp,i,j,romptr=0; if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSCART | SetCRT2ToHiVision | SetCRT2ToYPbPr525750)) return; @@ -12162,7 +11194,7 @@ SetOEMYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVYFilterIndex; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBType & VB_SIS30xBLV) { for(i=0x35, j=0; i<=0x38; i++, j++) { SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]); } @@ -12185,11 +11217,11 @@ SetOEMYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } } -static USHORT -SiS_SearchVBModeID(SiS_Private *SiS_Pr, USHORT *ModeNo) +static unsigned short +SiS_SearchVBModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo) { - USHORT ModeIdIndex; - UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO; + unsigned short ModeIdIndex; + unsigned char VGAINFO = SiS_Pr->SiS_VGAINFO; if(*ModeNo <= 5) *ModeNo |= 1; @@ -12210,10 +11242,10 @@ SiS_SearchVBModeID(SiS_Private *SiS_Pr, USHORT *ModeNo) } static void -SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo, USHORT ModeIdIndex, USHORT RefTableIndex) +SiS_OEM300Setting(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefTableIndex) { - USHORT OEMModeIdIndex=0; + unsigned short OEMModeIdIndex = 0; if(!SiS_Pr->UseCustomMode) { OEMModeIdIndex = SiS_SearchVBModeID(SiS_Pr,&ModeNo); @@ -12221,18 +11253,18 @@ SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, } if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - SetOEMLCDDelay(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex); + SetOEMLCDDelay(SiS_Pr, ModeNo, OEMModeIdIndex); if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - SetOEMLCDData(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex); + SetOEMLCDData(SiS_Pr, ModeNo, OEMModeIdIndex); } } if(SiS_Pr->UseCustomMode) return; if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - SetOEMTVDelay(SiS_Pr, HwInfo, ModeNo,OEMModeIdIndex); + SetOEMTVDelay(SiS_Pr, ModeNo,OEMModeIdIndex); if(SiS_Pr->SiS_VBType & VB_SISVB) { - SetOEMAntiFlicker(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex); - SetOEMPhaseIncr(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex); - SetOEMYFilter(SiS_Pr, HwInfo, ModeNo, OEMModeIdIndex); + SetOEMAntiFlicker(SiS_Pr, ModeNo, OEMModeIdIndex); + SetOEMPhaseIncr(SiS_Pr, ModeNo, OEMModeIdIndex); + SetOEMYFilter(SiS_Pr, ModeNo, OEMModeIdIndex); } } } diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h index f84eb54164a5d..f475b21a85cfa 100644 --- a/drivers/video/sis/init301.h +++ b/drivers/video/sis/init301.h @@ -3,7 +3,7 @@ /* * Data and prototypes for init301.c * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -50,18 +50,18 @@ * */ -#ifndef _INIT301_ -#define _INIT301_ +#ifndef _INIT301_H_ +#define _INIT301_H_ #include "osdef.h" #include "initdef.h" -#ifdef LINUX_XF86 +#ifdef SIS_XORG_XF86 #include "sis.h" #include "sis_regs.h" #endif -#ifdef LINUX_KERNEL +#ifdef SIS_LINUX_KERNEL #include "vgatypes.h" #include "vstruct.h" #ifdef SIS_CP @@ -69,8 +69,13 @@ #endif #include <linux/config.h> #include <linux/version.h> -#include <asm/io.h> #include <linux/types.h> +#include <asm/io.h> +#include <linux/fb.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include <video/fbcon.h> +#endif +#include "sis.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #include <linux/sisfb.h> #else @@ -78,7 +83,7 @@ #endif #endif -static const UCHAR SiS_YPbPrTable[3][64] = { +static const unsigned char SiS_YPbPrTable[3][64] = { { 0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c, 0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a, @@ -90,17 +95,17 @@ static const UCHAR SiS_YPbPrTable[3][64] = { 0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00 }, { - 0x1d,0x11,0x06,0x09,0x0b,0x0c,0x0c,0x0c, + 0x33,0x06,0x06,0x09,0x0b,0x0c,0x0c,0x0c, 0x98,0x0a,0x01,0x0d,0x06,0x0d,0x04,0x0a, 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, - 0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4c /*0x4f*/,0x13, + 0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4f,0x13, 0xad,0x11,0xad,0x1d,0x40,0x8a,0x3d,0xb8, - 0x51,0x5e,0x60,0x57 /*0x49*/,0x7b /*0x7d*/,0x92,0x0f,0x40, - 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x4b, + 0x51,0x5e,0x60,0x49,0x7d,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x4e, 0x43,0x41,0x11,0x00,0xfc,0xff,0x32,0x00 }, { -#if 1 +#if 0 /* OK, but sticks to left edge */ 0x13,0x1d,0xe8,0x09,0x09,0xed,0x0c,0x0c, 0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a, 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, @@ -110,20 +115,42 @@ static const UCHAR SiS_YPbPrTable[3][64] = { 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x27, 0x00,0x40,0x11,0x00,0xfc,0xff,0x32,0x00 #endif -#if 0 - 0x2a,0x14,0xe8,0x09,0x09,0xed,0x0c,0x0c, /* TEST (0.93) - BAD */ +#if 1 /* Perfect */ + 0x23,0x2d,0xe8,0x09,0x09,0xed,0x0c,0x0c, 0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a, 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, - 0xed,0x50,0x70,0x9e,0x16,0x57,0x6c,0x13, - 0x27,0x0b,0x27,0xfb,0x30,0x27,0x15,0xb0, - 0x3b,0xdb,0x61,0x24,0x78,0x92,0x0f,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0x14,0x6f, - 0x00,0x52,0xbb,0x00,0xd5,0xf7,0xa2,0x00 + 0xed,0x50,0x70,0x9f,0x16,0x59,0x60,0x13, + 0x27,0x0b,0x27,0xfc,0x30,0x27,0x1c,0xb0, + 0x4b,0x4b,0x6f,0x2f,0x63,0x92,0x0f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x73, + 0x00,0x40,0x11,0x00,0xfc,0xff,0x32,0x00 #endif } }; -static const UCHAR SiS_HiTVGroup3_1[] = { +static const unsigned char SiS_TVPhase[] = +{ + 0x21,0xED,0xBA,0x08, /* 0x00 SiS_NTSCPhase */ + 0x2A,0x05,0xE3,0x00, /* 0x01 SiS_PALPhase */ + 0x21,0xE4,0x2E,0x9B, /* 0x02 SiS_PALMPhase */ + 0x21,0xF4,0x3E,0xBA, /* 0x03 SiS_PALNPhase */ + 0x1E,0x8B,0xA2,0xA7, + 0x1E,0x83,0x0A,0xE0, /* 0x05 SiS_SpecialPhaseM */ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x21,0xF0,0x7B,0xD6, /* 0x08 SiS_NTSCPhase2 */ + 0x2A,0x09,0x86,0xE9, /* 0x09 SiS_PALPhase2 */ + 0x21,0xE6,0xEF,0xA4, /* 0x0a SiS_PALMPhase2 */ + 0x21,0xF6,0x94,0x46, /* 0x0b SiS_PALNPhase2 */ + 0x1E,0x8B,0xA2,0xA7, + 0x1E,0x83,0x0A,0xE0, /* 0x0d SiS_SpecialPhaseM */ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x1e,0x8c,0x5c,0x7a, /* 0x10 SiS_SpecialPhase */ + 0x25,0xd4,0xfd,0x5e /* 0x11 SiS_SpecialPhaseJ */ +}; + +static const unsigned char SiS_HiTVGroup3_1[] = { 0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x13, 0xb1, 0x41, 0x62, 0x62, 0xff, 0xf4, 0x45, 0xa6, 0x25, 0x2f, 0x67, 0xf6, 0xbf, 0xff, 0x8e, 0x20, @@ -134,7 +161,7 @@ static const UCHAR SiS_HiTVGroup3_1[] = { 0x1a, 0x1f, 0x25, 0x2a, 0x4c, 0xaa, 0x01 }; -static const UCHAR SiS_HiTVGroup3_2[] = { +static const unsigned char SiS_HiTVGroup3_2[] = { 0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x7a, 0x54, 0x41, 0xe7, 0xe7, 0xff, 0xf4, 0x45, 0xa6, 0x25, 0x2f, 0x67, 0xf6, 0xbf, 0xff, 0x8e, 0x20, @@ -147,7 +174,7 @@ static const UCHAR SiS_HiTVGroup3_2[] = { /* 301C / 302ELV extended Part2 TV registers (4 tap scaler) */ -static const UCHAR SiS_Part2CLVX_1[] = { +static const unsigned char SiS_Part2CLVX_1[] = { 0x00,0x00, 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F,0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E,0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, @@ -155,7 +182,7 @@ static const UCHAR SiS_Part2CLVX_1[] = { 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C,0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E }; -static const UCHAR SiS_Part2CLVX_2[] = { +static const unsigned char SiS_Part2CLVX_2[] = { 0x00,0x00, 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F,0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E,0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, @@ -163,7 +190,7 @@ static const UCHAR SiS_Part2CLVX_2[] = { 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C,0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E }; -static const UCHAR SiS_Part2CLVX_3[] = { /* NTSC, 525i, 525p */ +static const unsigned char SiS_Part2CLVX_3[] = { /* NTSC, 525i, 525p */ 0xE0,0x01, 0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D,0x01,0x1A,0x08,0x7D,0x00,0x19,0x0A,0x7D, 0x7F,0x19,0x0C,0x7C,0x7E,0x18,0x0E,0x7C,0x7E,0x17,0x10,0x7B,0x7D,0x15,0x12,0x7C, @@ -182,7 +209,7 @@ static const UCHAR SiS_Part2CLVX_3[] = { /* NTSC, 525i, 525p */ 0xFF,0xFF }; -static const UCHAR SiS_Part2CLVX_4[] = { /* PAL */ +static const unsigned char SiS_Part2CLVX_4[] = { /* PAL */ 0x58,0x02, 0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E,0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D, 0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C,0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D, @@ -201,7 +228,7 @@ static const UCHAR SiS_Part2CLVX_4[] = { /* PAL */ 0xFF,0xFF }; -static const UCHAR SiS_Part2CLVX_5[] = { /* 750p */ +static const unsigned char SiS_Part2CLVX_5[] = { /* 750p */ 0x00,0x03, 0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E,0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D, 0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C,0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D, @@ -210,7 +237,7 @@ static const UCHAR SiS_Part2CLVX_5[] = { /* 750p */ 0xFF,0xFF }; -static const UCHAR SiS_Part2CLVX_6[] = { /* 1080i */ +static const unsigned char SiS_Part2CLVX_6[] = { /* 1080i */ 0x00,0x04, 0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E,0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D, 0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D,0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C, @@ -221,7 +248,7 @@ static const UCHAR SiS_Part2CLVX_6[] = { /* 1080i */ #ifdef SIS315H /* 661 et al LCD data structure (2.03.00) */ -static const UCHAR SiS_LCDStruct661[] = { +static const unsigned char SiS_LCDStruct661[] = { /* 1024x768 */ /* type|CR37| HDE | VDE | HT | VT | hss | hse */ 0x02,0xC0,0x00,0x04,0x00,0x03,0x40,0x05,0x26,0x03,0x10,0x00,0x88, @@ -249,11 +276,20 @@ static const UCHAR SiS_LCDStruct661[] = { /* 1680x1050 */ 0x0D,0xE0,0x90,0x06,0x1A,0x04,0x6C,0x07,0x2A,0x04,0x1A,0x00,0x4C, 0x00,0x03,0x00,0x06,0x00,0x79,0xBE,0x44,0x00,0x00,0x00,0x00,0x06, + /* 1280x800_3 */ + 0x0C,0xE0,0x00,0x05,0x20,0x03,0xAA,0x05,0x2E,0x03,0x30,0x00,0x50, + 0x00,0x04,0x00,0x03,0x00,0x47,0xA9,0x10,0x00,0x00,0x00,0x00,0x07, + /* 800x600 */ + 0x01,0xC0,0x20,0x03,0x58,0x02,0x20,0x04,0x74,0x02,0x2A,0x00,0x80, + 0x00,0x06,0x00,0x04,0x00,0x28,0x63,0x4B,0x00,0x00,0x00,0x00,0x00, + /* 1280x854 */ + 0x08,0xE0,0x00,0x05,0x56,0x03,0x80,0x06,0x5d,0x03,0x10,0x00,0x70, + 0x00,0x01,0x00,0x03,0x00,0x54,0x75,0x13,0x00,0x00,0x00,0x00,0x08 }; #endif #ifdef SIS300 -static UCHAR SiS300_TrumpionData[7][80] = { +static unsigned char SiS300_TrumpionData[14][80] = { { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, 0x20,0x03,0x0B,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x10,0x00,0x00,0x04,0x23, 0x00,0x00,0x03,0x28,0x03,0x10,0x05,0x08,0x40,0x10,0x00,0x10,0x04,0x23,0x00,0x23, @@ -288,119 +324,182 @@ static UCHAR SiS300_TrumpionData[7][80] = { 0x40,0x05,0x13,0x00,0x00,0x03,0x26,0x03,0x88,0x0C,0x30,0x90,0x00,0x00,0x04,0x23, 0x00,0x01,0x03,0x24,0x03,0x28,0x06,0x08,0x40,0x90,0x00,0x90,0x04,0x23,0x00,0x23, 0x03,0x11,0x60,0x40,0x05,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x08,0x01,0x00,0x08,0x01, - 0x00,0x08,0x01,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 } + 0x00,0x08,0x01,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 }, + /* variant 2 */ + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x15,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x18,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x44,0x03,0x28,0x06,0x08,0x40,0x18,0x00,0x18,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xA6,0x01,0xFF,0x03,0xFF,0x19,0x01,0x00,0x05,0x13,0x04,0x04,0x05, + 0x04,0x0C,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x15,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x18,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x44,0x03,0x28,0x06,0x08,0x40,0x18,0x00,0x18,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xA6,0x01,0xFF,0x03,0xFF,0x19,0x01,0x00,0x05,0x13,0x04,0x04,0x05, + 0x04,0x0C,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0x8A,0x00,0xD8,0x02, + 0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23, + 0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xDA,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05, + 0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0x72,0x00,0xD8,0x02, + 0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23, + 0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xDA,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05, + 0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x02,0x00,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x16,0x00,0xE0,0x01,0x0D,0x02,0x60,0x0C,0x30,0x98,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x45,0x03,0x48,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xF4,0x01,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x05,0x01,0x00,0x05,0x05, + 0x04,0x0C,0x08,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEA,0x58,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x02,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0xBF,0x00,0x20,0x03, + 0x20,0x04,0x0D,0x00,0x58,0x02,0x71,0x02,0x80,0x0C,0x30,0x9A,0x00,0xFA,0x03,0x1D, + 0x00,0x01,0x03,0x22,0x03,0x28,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x1D,0x00,0x1D, + 0x03,0x11,0x60,0x39,0x03,0x40,0x05,0xF4,0x18,0x07,0x02,0x06,0x04,0x01,0x06,0x0B, + 0x02,0x0A,0x20,0x19,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEA,0x58,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x11,0x00,0x0D,0x10,0xEF,0x00,0x00,0x04, + 0x40,0x05,0x13,0x00,0x00,0x03,0x26,0x03,0x88,0x0C,0x30,0x90,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x24,0x03,0x28,0x06,0x08,0x40,0x90,0x00,0x90,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0x40,0x05,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x08,0x01,0x00,0x08,0x01, + 0x00,0x08,0x01,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEA,0x58,0x01,0xBE,0x01,0x00 } }; #endif -void SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -void SiS_EnableCRT2(SiS_Private *SiS_Pr); -USHORT SiS_GetRatePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo); -void SiS_WaitRetrace1(SiS_Private *SiS_Pr); -BOOLEAN SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -BOOLEAN SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -void SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo); -void SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, - USHORT ModeIdIndex, PSIS_HW_INFO HwInfo, - int checkcrt2mode); -void SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -void SiS_SetTVMode(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo); -void SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo); -USHORT SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo); -USHORT SiS_GetResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex); -void SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -BOOLEAN SiS_SetCRT2Group(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo); -void SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -void SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +void SiS_UnLockCRT2(struct SiS_Private *SiS_Pr); +#ifndef SIS_LINUX_KERNEL +void SiS_LockCRT2(struct SiS_Private *SiS_Pr); +#endif +void SiS_EnableCRT2(struct SiS_Private *SiS_Pr); +unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); +void SiS_WaitRetrace1(struct SiS_Private *SiS_Pr); +BOOLEAN SiS_IsDualEdge(struct SiS_Private *SiS_Pr); +BOOLEAN SiS_IsVAMode(struct SiS_Private *SiS_Pr); +void SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex, int checkcrt2mode); +void SiS_SetYPbPr(struct SiS_Private *SiS_Pr); +void SiS_SetTVMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +void SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +unsigned short SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex); +unsigned short SiS_GetResInfo(struct SiS_Private *SiS_Pr,unsigned short ModeNo,unsigned short ModeIdIndex); +void SiS_DisableBridge(struct SiS_Private *SiS_Pr); +#ifndef SIS_LINUX_KERNEL +void SiS_EnableBridge(struct SiS_Private *SiS_Pr); +#endif +BOOLEAN SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +void SiS_SiS30xBLOn(struct SiS_Private *SiS_Pr); +void SiS_SiS30xBLOff(struct SiS_Private *SiS_Pr); -void SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempax); -USHORT SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempax); -void SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempax); -USHORT SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempax); -void SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh); +void SiS_SetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); +unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short tempax); +void SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); +unsigned short SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short tempax); +#ifndef SIS_LINUX_KERNEL +void SiS_SetCH70xx(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); +unsigned short SiS_GetCH70xx(struct SiS_Private *SiS_Pr, unsigned short tempax); +#endif +void SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg, + unsigned char orval,unsigned short andval); #ifdef SIS315H -static void SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -static void SiS_Chrontel701xOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -static void SiS_ChrontelInitTVVSync(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -static void SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -void SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); -void SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr); +static void SiS_Chrontel701xOn(struct SiS_Private *SiS_Pr); +static void SiS_Chrontel701xOff(struct SiS_Private *SiS_Pr); +static void SiS_ChrontelInitTVVSync(struct SiS_Private *SiS_Pr); +static void SiS_ChrontelDoSomething1(struct SiS_Private *SiS_Pr); +void SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr); +void SiS_Chrontel701xBLOff(struct SiS_Private *SiS_Pr); #endif /* 315 */ #ifdef SIS300 -#if 0 -static void SiS_SetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx); -static USHORT SiS_GetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx); -#endif -static BOOLEAN SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr); +static BOOLEAN SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr); +void SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo); #endif -void SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime); -USHORT SiS_ReadDDC1Bit(SiS_Private *SiS_Pr); -USHORT SiS_HandleDDC(SiS_Private *SiS_Pr, ULONG VBFlags, int VGAEngine, - USHORT adaptnum, USHORT DDCdatatype, UCHAR *buffer); -#ifdef LINUX_XF86 -USHORT SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS); -USHORT SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SISPtr pSiS); -#endif +void SiS_DDC2Delay(struct SiS_Private *SiS_Pr, unsigned int delaytime); +unsigned short SiS_ReadDDC1Bit(struct SiS_Private *SiS_Pr); +unsigned short SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, + unsigned short adaptnum, unsigned short DDCdatatype, + unsigned char *buffer, unsigned int VBFlags2); -static void SiS_SetSwitchDDC2(SiS_Private *SiS_Pr); -static USHORT SiS_SetStart(SiS_Private *SiS_Pr); -static USHORT SiS_SetStop(SiS_Private *SiS_Pr); -static USHORT SiS_SetSCLKLow(SiS_Private *SiS_Pr); -static USHORT SiS_SetSCLKHigh(SiS_Private *SiS_Pr); -static USHORT SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax); -static USHORT SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax); -static USHORT SiS_CheckACK(SiS_Private *SiS_Pr); -static USHORT SiS_InitDDCRegs(SiS_Private *SiS_Pr, ULONG VBFlags, int VGAEngine, - USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32); -static USHORT SiS_WriteDABDDC(SiS_Private *SiS_Pr); -static USHORT SiS_PrepareReadDDC(SiS_Private *SiS_Pr); -static USHORT SiS_PrepareDDC(SiS_Private *SiS_Pr); -static void SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno); -static USHORT SiS_DoProbeDDC(SiS_Private *SiS_Pr); -static USHORT SiS_ProbeDDC(SiS_Private *SiS_Pr); -static USHORT SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, UCHAR *buffer); +#ifdef SIS_XORG_XF86 +unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, + int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype, + BOOLEAN checkcr32, unsigned int VBFlags2); +unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr); +unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype, + unsigned char *buffer); +#else +static unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, + int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype, + BOOLEAN checkcr32, unsigned int VBFlags2); +static unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr); +static unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype, + unsigned char *buffer); +#endif +static void SiS_SetSwitchDDC2(struct SiS_Private *SiS_Pr); +static unsigned short SiS_SetStart(struct SiS_Private *SiS_Pr); +static unsigned short SiS_SetStop(struct SiS_Private *SiS_Pr); +static unsigned short SiS_SetSCLKLow(struct SiS_Private *SiS_Pr); +static unsigned short SiS_SetSCLKHigh(struct SiS_Private *SiS_Pr); +static unsigned short SiS_ReadDDC2Data(struct SiS_Private *SiS_Pr); +static unsigned short SiS_WriteDDC2Data(struct SiS_Private *SiS_Pr, unsigned short tempax); +static unsigned short SiS_CheckACK(struct SiS_Private *SiS_Pr); +static unsigned short SiS_WriteDABDDC(struct SiS_Private *SiS_Pr); +static unsigned short SiS_PrepareReadDDC(struct SiS_Private *SiS_Pr); +static unsigned short SiS_PrepareDDC(struct SiS_Private *SiS_Pr); +static void SiS_SendACK(struct SiS_Private *SiS_Pr, unsigned short yesno); +static unsigned short SiS_DoProbeDDC(struct SiS_Private *SiS_Pr); +#ifdef SIS300 +static void SiS_OEM300Setting(struct SiS_Private *SiS_Pr, + unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefTabindex); +static void SetOEMLCDData2(struct SiS_Private *SiS_Pr, + unsigned short ModeNo, unsigned short ModeIdIndex,unsigned short RefTableIndex); +#endif #ifdef SIS315H -static void SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI); -static void SiS_OEM661Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI); -static void SiS_FinalizeLCD(SiS_Private *, USHORT, USHORT, PSIS_HW_INFO); +static void SiS_OEM310Setting(struct SiS_Private *SiS_Pr, + unsigned short ModeNo,unsigned short ModeIdIndex, unsigned short RRTI); +static void SiS_OEM661Setting(struct SiS_Private *SiS_Pr, + unsigned short ModeNo,unsigned short ModeIdIndex, unsigned short RRTI); +static void SiS_FinalizeLCD(struct SiS_Private *, unsigned short, unsigned short); #endif + +extern void SiS_SetReg(SISIOADDRESS, unsigned short, unsigned short); +extern void SiS_SetRegByte(SISIOADDRESS, unsigned short); +extern void SiS_SetRegShort(SISIOADDRESS, unsigned short); +extern void SiS_SetRegLong(SISIOADDRESS, unsigned int); +extern unsigned char SiS_GetReg(SISIOADDRESS, unsigned short); +extern unsigned char SiS_GetRegByte(SISIOADDRESS); +extern unsigned short SiS_GetRegShort(SISIOADDRESS); +extern unsigned int SiS_GetRegLong(SISIOADDRESS); +extern void SiS_SetRegANDOR(SISIOADDRESS, unsigned short, unsigned short, unsigned short); +extern void SiS_SetRegOR(SISIOADDRESS, unsigned short, unsigned short); +extern void SiS_SetRegAND(SISIOADDRESS, unsigned short, unsigned short); +extern void SiS_DisplayOff(struct SiS_Private *SiS_Pr); +extern void SiS_DisplayOn(struct SiS_Private *SiS_Pr); +extern BOOLEAN SiS_SearchModeID(struct SiS_Private *, unsigned short *, unsigned short *); +extern unsigned short SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern unsigned short SiS_GetModePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); +extern unsigned short SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex); +extern unsigned short SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex, + unsigned short RefreshRateTableIndex); +extern void SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern void SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo, + unsigned short ModeIdIndex); +extern void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth); +extern unsigned short SiS_GetRefCRTVCLK(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide); +extern unsigned short SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide); #ifdef SIS300 -static void SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo, USHORT ModeIdIndex, USHORT RefTabindex); -static void SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, - USHORT ModeNo, USHORT ModeIdIndex,USHORT RefTableIndex); +extern void SiS_GetFIFOThresholdIndex300(struct SiS_Private *SiS_Pr, unsigned short *tempbx, + unsigned short *tempcl); +extern unsigned short SiS_GetFIFOThresholdB300(unsigned short tempbx, unsigned short tempcl); +extern unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned short index); +#ifdef SIS_LINUX_KERNEL +extern unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg); +extern unsigned int sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg); #endif - -extern void SiS_SetReg(SISIOADDRESS, USHORT, USHORT); -extern void SiS_SetRegByte(SISIOADDRESS, USHORT); -extern void SiS_SetRegShort(SISIOADDRESS, USHORT); -extern void SiS_SetRegLong(SISIOADDRESS, ULONG); -extern UCHAR SiS_GetReg(SISIOADDRESS, USHORT); -extern UCHAR SiS_GetRegByte(SISIOADDRESS); -extern USHORT SiS_GetRegShort(SISIOADDRESS); -extern ULONG SiS_GetRegLong(SISIOADDRESS); -extern void SiS_SetRegANDOR(SISIOADDRESS, USHORT, USHORT, USHORT); -extern void SiS_SetRegOR(SISIOADDRESS, USHORT, USHORT); -extern void SiS_SetRegAND(SISIOADDRESS, USHORT, USHORT); -extern void SiS_DisplayOff(SiS_Private *SiS_Pr); -extern void SiS_DisplayOn(SiS_Private *SiS_Pr); -extern BOOLEAN SiS_SearchModeID(SiS_Private *, USHORT *, USHORT *); -extern UCHAR SiS_GetModePtr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); -extern USHORT SiS_GetColorDepth(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); -extern USHORT SiS_GetOffset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo); -extern void SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO, USHORT ModeNo, - USHORT ModeIdIndex); -extern void SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex); -#ifdef LINUX_XF86 -extern void SiS_MakeClockRegs(ScrnInfoPtr pScrn, int clock, UCHAR *p2b, UCHAR *p2c); -extern int SiS_FindPanelFromDB(SISPtr pSiS, USHORT panelvendor, USHORT panelproduct, - int *maxx, int *maxy, int *prefx, int *prefy); #endif #endif diff --git a/drivers/video/sis/initdef.h b/drivers/video/sis/initdef.h index 55a82d6dc4cfd..264b55a5947b8 100644 --- a/drivers/video/sis/initdef.h +++ b/drivers/video/sis/initdef.h @@ -3,7 +3,7 @@ /* * Global definitions for init.c and init301.c * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -53,19 +53,20 @@ #ifndef _INITDEF_ #define _INITDEF_ -#define IS_SIS330 (HwInfo->jChipType == SIS_330) -#define IS_SIS550 (HwInfo->jChipType == SIS_550) -#define IS_SIS650 (HwInfo->jChipType == SIS_650) /* All versions, incl 651, M65x */ -#define IS_SIS740 (HwInfo->jChipType == SIS_740) +#define IS_SIS330 (SiS_Pr->ChipType == SIS_330) +#define IS_SIS550 (SiS_Pr->ChipType == SIS_550) +#define IS_SIS650 (SiS_Pr->ChipType == SIS_650) /* All versions, incl 651, M65x */ +#define IS_SIS740 (SiS_Pr->ChipType == SIS_740) #define IS_SIS651 (SiS_Pr->SiS_SysFlags & (SF_Is651 | SF_Is652)) #define IS_SISM650 (SiS_Pr->SiS_SysFlags & (SF_IsM650 | SF_IsM652 | SF_IsM653)) #define IS_SIS65x (IS_SIS651 || IS_SISM650) /* Only special versions of 65x */ -#define IS_SIS661 (HwInfo->jChipType == SIS_661) -#define IS_SIS741 (HwInfo->jChipType == SIS_741) -#define IS_SIS660 (HwInfo->jChipType == SIS_660) -#define IS_SIS760 (HwInfo->jChipType == SIS_760) -#define IS_SIS661741660760 (IS_SIS661 || IS_SIS741 || IS_SIS660 || IS_SIS760) -#define IS_SIS650740 ((HwInfo->jChipType >= SIS_650) && (HwInfo->jChipType < SIS_330)) +#define IS_SIS661 (SiS_Pr->ChipType == SIS_661) +#define IS_SIS741 (SiS_Pr->ChipType == SIS_741) +#define IS_SIS660 (SiS_Pr->ChipType == SIS_660) +#define IS_SIS760 (SiS_Pr->ChipType == SIS_760) +#define IS_SIS761 (SiS_Pr->ChipType == SIS_761) +#define IS_SIS661741660760 (IS_SIS661 || IS_SIS741 || IS_SIS660 || IS_SIS760 || IS_SIS761) +#define IS_SIS650740 ((SiS_Pr->ChipType >= SIS_650) && (SiS_Pr->ChipType < SIS_330)) #define IS_SIS550650740 (IS_SIS550 || IS_SIS650740) #define IS_SIS650740660 (IS_SIS650 || IS_SIS740 || IS_SIS661741660760) #define IS_SIS550650740660 (IS_SIS550 || IS_SIS650740660) @@ -73,24 +74,37 @@ #define SISGETROMW(x) (ROMAddr[(x)] | (ROMAddr[(x)+1] << 8)) /* SiS_VBType */ -#define VB_SIS301 0x0001 -#define VB_SIS301B 0x0002 -#define VB_SIS302B 0x0004 -#define VB_SIS301LV 0x0008 -#define VB_SIS302LV 0x0010 +#define VB_SIS301 0x0001 +#define VB_SIS301B 0x0002 +#define VB_SIS302B 0x0004 +#define VB_SIS301LV 0x0008 +#define VB_SIS302LV 0x0010 #define VB_SIS302ELV 0x0020 -#define VB_SIS301C 0x0040 +#define VB_SIS301C 0x0040 +#define VB_SIS307T 0x0080 +#define VB_SIS307LV 0x0100 #define VB_UMC 0x4000 #define VB_NoLCD 0x8000 -#define VB_SIS301BLV302BLV (VB_SIS301B|VB_SIS301C|VB_SIS302B|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV) -#define VB_SIS301B302B (VB_SIS301B|VB_SIS301C|VB_SIS302B) -#define VB_SIS301LV302LV (VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV) -#define VB_SISVB (VB_SIS301 | VB_SIS301BLV302BLV) -#define VB_SISTMDS (VB_SIS301 | VB_SIS301B302B) -#define VB_SISLVDS VB_SIS301LV302LV -#define VB_SISLCDA (VB_SIS302B|VB_SIS301C|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV) -#define VB_SISYPBPR (VB_SIS301C|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV) -#define VB_SISHIVISION (VB_SIS301|VB_SIS301B|VB_SIS302B) +#define VB_SIS30xB (VB_SIS301B | VB_SIS301C | VB_SIS302B | VB_SIS307T) +#define VB_SIS30xC (VB_SIS301C | VB_SIS307T) +#define VB_SISTMDS (VB_SIS301 | VB_SIS301B | VB_SIS301C | VB_SIS302B | VB_SIS307T) +#define VB_SISLVDS (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV | VB_SIS307LV) +#define VB_SIS30xBLV (VB_SIS30xB | VB_SISLVDS) +#define VB_SIS30xCLV (VB_SIS30xC | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISVB (VB_SIS301 | VB_SIS30xBLV) +#define VB_SISLCDA (VB_SIS302B | VB_SIS301C | VB_SIS307T | VB_SISLVDS) +#define VB_SISTMDSLCDA (VB_SIS301C | VB_SIS307T) +#define VB_SISPART4SCALER (VB_SIS301C | VB_SIS307T | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISHIVISION (VB_SIS301 | VB_SIS301B | VB_SIS302B) +#define VB_SISYPBPR (VB_SIS301C | VB_SIS307T | VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISTAP4SCALER (VB_SIS301C | VB_SIS307T | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISPART4OVERFLOW (VB_SIS301C | VB_SIS307T | VB_SIS302LV | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISPWD (VB_SIS301C | VB_SIS307T | VB_SISLVDS) +#define VB_SISEMI (VB_SIS302LV | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISPOWER (VB_SIS301C | VB_SIS307T | VB_SIS302LV | VB_SIS302ELV | VB_SIS307LV) +#define VB_SISDUALLINK (VB_SIS302LV | VB_SIS302ELV | VB_SIS307T | VB_SIS307LV) +#define VB_SISVGA2 VB_SISTMDS +#define VB_SISRAMDAC202 (VB_SIS301C | VB_SIS307T) /* VBInfo */ #define SetSimuScanMode 0x0001 /* CR 30 */ @@ -160,6 +174,7 @@ #define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ #define InterlaceMode 0x0080 #define SyncPP 0x0000 +#define HaveWideTiming 0x2000 /* Have specific wide- and non-wide timing */ #define SyncPN 0x4000 #define SyncNP 0x8000 #define SyncNN 0xc000 @@ -188,6 +203,7 @@ #define TVSetTVSimuMode 0x0200 /* new 0x200, prev. 0x800 */ #define TVRPLLDIV2XO 0x0400 /* prev 0x1000 */ #define TVSetNTSC1024 0x0800 /* new 0x100, prev. 0x2000 */ +#define TVSet525p1024 0x1000 /* TW */ #define TVAspect43 0x2000 #define TVAspect169 0x4000 #define TVAspect43LB 0x8000 @@ -208,7 +224,8 @@ #define SF_IsM661 0x0020 #define SF_IsM741 0x0040 #define SF_IsM760 0x0080 -#define SF_760LFB 0x8000 /* 760: We have LFB */ +#define SF_760UMA 0x4000 /* 76x: We have UMA */ +#define SF_760LFB 0x8000 /* 76x: We have LFB */ /* CR32 (Newer 630, and 315 series) @@ -228,25 +245,19 @@ #define TVOverScanShift 4 /* CR35 (661 series only) - [0] 1 = PAL, 0 = NTSC [1] 1 = NTSC-J (if D0 = 0) [2] 1 = PALM (if D0 = 1) [3] 1 = PALN (if D0 = 1) [4] 1 = Overscan (Chrontel only) [7:5] (only if D2 in CR38 is set) - 000 525i - 001 525p + 000 525i + 001 525p 010 750p 011 1080i (or HiVision on 301, 301B) - - These bits are being translated to TVMode flag. - */ -/* - CR37 - +/* CR37 [0] Set 24/18 bit (0/1) RGB to LVDS/TMDS transmitter (set by BIOS) [3:1] External chip 300 series: @@ -260,7 +271,7 @@ 010 LVDS 011 LVDS + Chrontel 7019 660 series [2:1] only: - reserved (now in CR38) + reserved (chip type now in CR38) All other combinations reserved [3] 661 only: Pass 1:1 data [4] LVDS: 0: Panel Link expands / 1: Panel Link does not expand @@ -320,6 +331,7 @@ #define Enable302LV_DualLink 0x04 /* 302LV only; enable dual link */ /* CR39 (661 and later) + D[7] LVDS (SiS or third party) D[1:0] YPbPr Aspect Ratio 00 4:3 letterbox 01 4:3 @@ -341,7 +353,7 @@ 0101 Set Contrast event 0110 Set Mute event 0111 Set Volume Up/Down event - [4] Enable Backlight Control by BIOS/driver + [4] Enable Backlight Control by BIOS/driver (set by driver; set means that the BIOS should not touch the backlight registers because eg. the driver already switched off the backlight) @@ -350,6 +362,26 @@ [7] TV UnderScan/OverScan (set by BIOS) */ +/* CR7C - 661 and later + [7] DualEdge enabled (or: to be enabled) + [6] CRT2 = TV/LCD/VGA enabled (or: to be enabled) + [5] Init done (set at end of SiS_Init) + {4] LVDS LCD capabilities + [3] LVDS LCD capabilities + [2] LVDS LCD capabilities (PWD) + [1] LVDS LCD capabilities (PWD) + [0] LVDS=1, TMDS=0 (SiS or third party) +*/ + +/* CR7E - 661 and later + VBType: + [7] LVDS (third party) + [3] 301C + [2] 302LV + [1] 301LV + [0] 301B +*/ + /* LCDResInfo */ #define Panel300_800x600 0x01 /* CR36 */ #define Panel300_1024x768 0x02 @@ -359,7 +391,6 @@ #define Panel300_1024x600 0x06 #define Panel300_1152x768 0x07 #define Panel300_1280x768 0x0a -#define Panel300_320x480 0x0e /* fstn - This is fake, can be any */ #define Panel300_Custom 0x0f #define Panel300_Barco1366 0x10 @@ -374,9 +405,9 @@ #define Panel310_1400x1050 0x09 #define Panel310_1280x768 0x0a #define Panel310_1600x1200 0x0b -#define Panel310_640x480_2 0x0c -#define Panel310_640x480_3 0x0d -#define Panel310_320x480 0x0e /* fstn - TW: This is fake, can be any */ +#define Panel310_320x240_2 0x0c /* xSTN */ +#define Panel310_320x240_3 0x0d /* xSTN */ +#define Panel310_320x240_1 0x0e /* xSTN - This is fake, can be any */ #define Panel310_Custom 0x0f #define Panel661_800x600 0x01 @@ -386,7 +417,7 @@ #define Panel661_1024x600 0x05 #define Panel661_1152x864 0x06 #define Panel661_1280x960 0x07 -#define Panel661_1152x768 0x08 +#define Panel661_1280x854 0x08 #define Panel661_1400x1050 0x09 #define Panel661_1280x768 0x0a #define Panel661_1600x1200 0x0b @@ -410,14 +441,16 @@ #define Panel_1680x1050 0x0d /* 661etc */ #define Panel_1280x720 0x0e /* 661etc */ #define Panel_Custom 0x0f /* MUST BE 0x0f (for DVI DDC detection) */ -#define Panel_320x480 0x10 /* SiS 550 fstn - TW: This is fake, can be any */ +#define Panel_320x240_1 0x10 /* SiS 550 xSTN */ #define Panel_Barco1366 0x11 #define Panel_848x480 0x12 -#define Panel_640x480_2 0x13 /* SiS 550 */ -#define Panel_640x480_3 0x14 /* SiS 550 */ +#define Panel_320x240_2 0x13 /* SiS 550 xSTN */ +#define Panel_320x240_3 0x14 /* SiS 550 xSTN */ #define Panel_1280x768_2 0x15 /* 30xLV */ #define Panel_1280x768_3 0x16 /* (unused) */ #define Panel_1280x800_2 0x17 /* 30xLV */ +#define Panel_856x480 0x18 +#define Panel_1280x854 0x19 /* 661etc */ /* Index in ModeResInfo table */ #define SIS_RI_320x200 0 @@ -454,6 +487,7 @@ #define SIS_RI_1920x1080 31 #define SIS_RI_960x540 32 #define SIS_RI_960x600 33 +#define SIS_RI_1280x854 34 /* CR5F */ #define IsM650 0x80 @@ -482,16 +516,18 @@ #define VCLK100_300 0x43 /* Index in VCLKData table (300) */ #define VCLK34_300 0x3d /* Index in VCLKData table (300) */ #define VCLK_CUSTOM_300 0x47 -#define VCLK65_315 0x0b /* Index in (VB)VCLKData table (315) */ -#define VCLK108_2_315 0x19 /* Index in (VB)VCLKData table (315) */ -#define VCLK81_315 0x5b /* Index in (VB)VCLKData table (315) */ -#define VCLK162_315 0x5e /* Index in (VB)VCLKData table (315) */ -#define VCLK108_3_315 0x45 /* Index in VBVCLKData table (315) */ -#define VCLK100_315 0x46 /* Index in VBVCLKData table (315) */ + +#define VCLK65_315 0x0b /* Indices in (VB)VCLKData table (315) */ +#define VCLK108_2_315 0x19 +#define VCLK81_315 0x5b +#define VCLK162_315 0x5e +#define VCLK108_3_315 0x45 +#define VCLK100_315 0x46 #define VCLK34_315 0x55 #define VCLK68_315 0x0d -#define VCLK_1280x800_315_2 0x5c /* Index in VBVCLKData table (315) */ -#define VCLK121_315 0x5d /* Index in VBVCLKData table (315) */ +#define VCLK_1280x800_315_2 0x5c +#define VCLK121_315 0x5d +#define VCLK130_315 0x72 #define VCLK_1280x720 0x5f #define VCLK_1280x768_2 0x60 #define VCLK_1280x768_3 0x61 /* (unused?) */ @@ -507,6 +543,7 @@ #define VCLK_1152x864 0x64 #define VCLK_1360x768 0x58 #define VCLK_1280x800_315 0x6c +#define VCLK_1280x854 0x76 #define TVCLKBASE_300 0x21 /* Indices on TV clocks in VCLKData table (300) */ #define TVCLKBASE_315 0x3a /* Indices on TV clocks in (VB)VCLKData table (315) */ diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c new file mode 100644 index 0000000000000..cc856d90903c1 --- /dev/null +++ b/drivers/video/sis/initextlfb.c @@ -0,0 +1,238 @@ +/* + * SiS 300/540/630[S]/730[S] + * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX] + * XGI V3XT/V5/V8, Z7 + * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 + * + * Linux kernel specific extensions to init.c/init301.c + * + * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria. + * + * 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 named License, + * or 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 + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + */ + +#include "osdef.h" +#include "initdef.h" +#include "vgatypes.h" +#include "vstruct.h" + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/types.h> +#include <linux/fb.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, + unsigned char modeno, unsigned char rateindex); +int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, + unsigned char rateindex, struct fb_var_screeninfo *var); +#endif +BOOLEAN sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, + int *htotal, int *vtotal, unsigned char rateindex); + +extern BOOLEAN SiSInitPtr(struct SiS_Private *SiS_Pr); +extern BOOLEAN SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, + unsigned short *ModeIdIndex); +extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, + int xres, int yres, struct fb_var_screeninfo *var, BOOLEAN writeres); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +int +sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno, + unsigned char rateindex) +{ + unsigned short ModeNo = modeno; + unsigned short ModeIdIndex = 0, ClockIndex = 0; + unsigned short RRTI = 0; + int Clock; + + if(!SiSInitPtr(SiS_Pr)) return 65000; + + if(rateindex > 0) rateindex--; + +#ifdef SIS315H + switch(ModeNo) { + case 0x5a: ModeNo = 0x50; break; + case 0x5b: ModeNo = 0x56; + } +#endif + + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {; + printk(KERN_ERR "Could not find mode %x\n", ModeNo); + return 65000; + } + + RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { + if(SiS_Pr->SiS_UseWide == 1) { + /* Wide screen: Ignore rateindex */ + ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_WIDE; + } else { + RRTI += rateindex; + ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK_NORM; + } + } else { + RRTI += rateindex; + ClockIndex = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRTVCLK; + } + + Clock = SiS_Pr->SiS_VCLKData[ClockIndex].CLOCK * 1000; + + return Clock; +} + +int +sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, + unsigned char rateindex, struct fb_var_screeninfo *var) +{ + unsigned short ModeNo = modeno; + unsigned short ModeIdIndex = 0, index = 0, RRTI = 0; + int j; + + if(!SiSInitPtr(SiS_Pr)) return 0; + + if(rateindex > 0) rateindex--; + +#ifdef SIS315H + switch(ModeNo) { + case 0x5a: ModeNo = 0x50; break; + case 0x5b: ModeNo = 0x56; + } +#endif + + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0; + + RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { + if(SiS_Pr->SiS_UseWide == 1) { + /* Wide screen: Ignore rateindex */ + index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE; + } else { + RRTI += rateindex; + index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM; + } + } else { + RRTI += rateindex; + index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC; + } + + SiS_Generic_ConvertCRData(SiS_Pr, + (unsigned char *)&SiS_Pr->SiS_CRT1Table[index].CR[0], + SiS_Pr->SiS_RefIndex[RRTI].XRes, + SiS_Pr->SiS_RefIndex[RRTI].YRes, + var, FALSE); + + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x8000) + var->sync &= ~FB_SYNC_VERT_HIGH_ACT; + else + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x4000) + var->sync &= ~FB_SYNC_HOR_HIGH_ACT; + else + var->sync |= FB_SYNC_HOR_HIGH_ACT; + + var->vmode = FB_VMODE_NONINTERLACED; + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x0080) + var->vmode = FB_VMODE_INTERLACED; + else { + j = 0; + while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) { + if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID == + SiS_Pr->SiS_RefIndex[RRTI].ModeID) { + if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) { + var->vmode = FB_VMODE_DOUBLE; + } + break; + } + j++; + } + } + + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { +#if 0 /* Do this? */ + var->upper_margin <<= 1; + var->lower_margin <<= 1; + var->vsync_len <<= 1; +#endif + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + var->upper_margin >>= 1; + var->lower_margin >>= 1; + var->vsync_len >>= 1; + } + + return 1; +} +#endif /* Linux >= 2.5 */ + +BOOLEAN +sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *htotal, + int *vtotal, unsigned char rateindex) +{ + unsigned short ModeNo = modeno; + unsigned short ModeIdIndex = 0, CRT1Index = 0; + unsigned short RRTI = 0; + unsigned char sr_data, cr_data, cr_data2; + + if(!SiSInitPtr(SiS_Pr)) return FALSE; + + if(rateindex > 0) rateindex--; + +#ifdef SIS315H + switch(ModeNo) { + case 0x5a: ModeNo = 0x50; break; + case 0x5b: ModeNo = 0x56; + } +#endif + + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE; + + RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) { + if(SiS_Pr->SiS_UseWide == 1) { + /* Wide screen: Ignore rateindex */ + CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_WIDE; + } else { + RRTI += rateindex; + CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC_NORM; + } + } else { + RRTI += rateindex; + CRT1Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT1CRTC; + } + + sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; + cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0]; + *htotal = (((cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8)) + 5) * 8; + + sr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; + cr_data = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6]; + cr_data2 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7]; + *vtotal = ((cr_data & 0xFF) | + ((unsigned short)(cr_data2 & 0x01) << 8) | + ((unsigned short)(cr_data2 & 0x20) << 4) | + ((unsigned short)(sr_data & 0x01) << 10)) + 2; + + if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & InterlaceMode) + *vtotal *= 2; + + return TRUE; +} + + + diff --git a/drivers/video/sis/oem300.h b/drivers/video/sis/oem300.h index b1358b750f53c..b73f268401434 100644 --- a/drivers/video/sis/oem300.h +++ b/drivers/video/sis/oem300.h @@ -3,7 +3,7 @@ /* * OEM Data for 300 series * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -50,7 +50,7 @@ * */ -static const UCHAR SiS300_OEMTVDelay301[8][4] = +static const unsigned char SiS300_OEMTVDelay301[8][4] = { {0x08,0x08,0x08,0x08}, {0x08,0x08,0x08,0x08}, @@ -62,7 +62,7 @@ static const UCHAR SiS300_OEMTVDelay301[8][4] = {0x20,0x20,0x20,0x20} }; -static const UCHAR SiS300_OEMTVDelayLVDS[8][4] = +static const unsigned char SiS300_OEMTVDelayLVDS[8][4] = { {0x20,0x20,0x20,0x20}, {0x20,0x20,0x20,0x20}, @@ -74,7 +74,7 @@ static const UCHAR SiS300_OEMTVDelayLVDS[8][4] = {0x20,0x20,0x20,0x20} }; -static const UCHAR SiS300_OEMTVFlicker[8][4] = +static const unsigned char SiS300_OEMTVFlicker[8][4] = { {0x00,0x00,0x00,0x00}, {0x00,0x00,0x00,0x00}, @@ -86,25 +86,7 @@ static const UCHAR SiS300_OEMTVFlicker[8][4] = {0x00,0x00,0x00,0x00} }; -#if 0 /* TW: Not used */ -static const UCHAR SiS300_OEMLCDDelay1[12][4]={ - {0x2c,0x2c,0x2c,0x2c}, - {0x20,0x20,0x20,0x20}, - {0x20,0x20,0x20,0x20}, - {0x2c,0x2c,0x2c,0x2c}, - {0x2c,0x2c,0x2c,0x2c}, - {0x20,0x20,0x20,0x20}, - {0x20,0x20,0x20,0x20}, - {0x24,0x24,0x24,0x24}, - {0x24,0x24,0x24,0x24}, - {0x20,0x20,0x20,0x20}, - {0x20,0x20,0x20,0x20}, - {0x24,0x24,0x24,0x24} -}; -#endif - -/* From 630/301B BIOS */ -static const UCHAR SiS300_OEMLCDDelay2[64][4] = /* for 301/301b/302b/301LV/302LV */ +static const unsigned char SiS300_OEMLCDDelay2[64][4] = /* for 301/301b/302b/301LV/302LV */ { {0x20,0x20,0x20,0x20}, {0x20,0x20,0x20,0x20}, @@ -172,8 +154,7 @@ static const UCHAR SiS300_OEMLCDDelay2[64][4] = /* for 301/301b/302b/301LV/302 {0x20,0x20,0x20,0x20} }; -/* From 300/301LV BIOS */ -static const UCHAR SiS300_OEMLCDDelay4[12][4] = +static const unsigned char SiS300_OEMLCDDelay4[12][4] = { {0x2c,0x2c,0x2c,0x2c}, {0x20,0x20,0x20,0x20}, @@ -189,8 +170,7 @@ static const UCHAR SiS300_OEMLCDDelay4[12][4] = {0x24,0x24,0x24,0x24} }; -/* From 300/301LV BIOS */ -static const UCHAR SiS300_OEMLCDDelay5[32][4] = +static const unsigned char SiS300_OEMLCDDelay5[32][4] = { {0x20,0x20,0x20,0x20}, {0x20,0x20,0x20,0x20}, @@ -226,8 +206,8 @@ static const UCHAR SiS300_OEMLCDDelay5[32][4] = {0x20,0x20,0x20,0x20}, }; -/* Added for LVDS */ -static const UCHAR SiS300_OEMLCDDelay3[64][4] = { /* For LVDS */ +static const unsigned char SiS300_OEMLCDDelay3[64][4] = /* For LVDS */ +{ {0x20,0x20,0x20,0x20}, {0x20,0x20,0x20,0x20}, {0x20,0x20,0x20,0x20}, @@ -294,7 +274,7 @@ static const UCHAR SiS300_OEMLCDDelay3[64][4] = { /* For LVDS */ {0x20,0x20,0x20,0x20} }; -static const UCHAR SiS300_Phase1[8][5][4] = +static const unsigned char SiS300_Phase1[8][5][4] = { { {0x21,0xed,0x00,0x08}, @@ -354,11 +334,10 @@ static const UCHAR SiS300_Phase1[8][5][4] = } }; - -static const UCHAR SiS300_Phase2[8][5][4] = +static const unsigned char SiS300_Phase2[8][5][4] = { { - {0x21,0xed,0x00,0x08}, + {0x21,0xed,0x00,0x08}, {0x21,0xed,0x8a,0x08}, {0x21,0xed,0x8a,0x08}, {0x21,0xed,0x8a,0x08}, @@ -372,42 +351,42 @@ static const UCHAR SiS300_Phase2[8][5][4] = {0x2a,0x05,0xd3,0x00} }, { - {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00} }, { - {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00} }, { - {0x21,0xed,0x00,0x08}, + {0x21,0xed,0x00,0x08}, {0x21,0xed,0x8a,0x08}, {0x21,0xed,0x8a,0x08}, {0x21,0xed,0x8a,0x08}, {0x21,0xed,0x8a,0x08} }, { - {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00} }, { - {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00} }, { - {0x2a,0x05,0xd3,0x00}, + {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00}, @@ -415,7 +394,7 @@ static const UCHAR SiS300_Phase2[8][5][4] = } }; -static const UCHAR SiS300_Filter1[10][16][4] = +static const unsigned char SiS300_Filter1[10][16][4] = { { {0x00,0xf4,0x10,0x38}, @@ -599,7 +578,7 @@ static const UCHAR SiS300_Filter1[10][16][4] = }, }; -static const UCHAR SiS300_Filter2[10][9][7] = +static const unsigned char SiS300_Filter2[10][9][7] = { { {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, @@ -714,142 +693,144 @@ static const UCHAR SiS300_Filter2[10][9][7] = }; /* Custom data for Barco iQ Pro R300 */ -static const UCHAR barco_p1[2][9][7][3] = { - { - { { 0x16, 0xcf, 0x00 }, - { 0x18, 0x00, 0x00 }, - { 0x1a, 0xe7, 0x00 }, - { 0x1b, 0x26, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x19, 0x00 } - }, - { - { 0x16, 0xcf, 0x00 }, - { 0x18, 0x00, 0x00 }, - { 0x1a, 0xe7, 0x00 }, - { 0x1b, 0x1e, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x16, 0x00 } - }, - { - { 0x16, 0xcf, 0x00 }, - { 0x1a, 0xe7, 0x00 }, - { 0x1b, 0x26, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x19, 0x00 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 } - }, - { - { 0x16, 0xcf, 0x00 }, - { 0x1a, 0xe7, 0x00 }, - { 0x1b, 0x26, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x1e, 0x00 }, - { 0, 0, 0 } - }, - { - { 0x16, 0xd1, 0x00 }, - { 0x18, 0x00, 0x00 }, - { 0x1a, 0xe7, 0x00 }, - { 0x1b, 0x11, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x26, 0x00 } - }, - { - { 0x16, 0xd1, 0x00 }, - { 0x1a, 0xe7, 0x00 }, - { 0x1b, 0x26, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x30, 0x00 }, - { 0, 0, 0 } - }, - { - { 0x16, 0x00, 0x00 }, - { 0x17, 0xa0, 0x00 }, - { 0x1a, 0xa0, 0x00 }, - { 0x1b, 0x2a, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0, 0, 0 } - }, - { - { 0x16, 0x00, 0x00 }, - { 0x17, 0xaa, 0x00 }, - { 0x1a, 0xa0, 0x00 }, - { 0x1b, 0x2a, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0, 0, 0 } - } - }, - { - { - { 0x16, 0xcf, 0x00 }, - { 0x18, 0x00, 0x00 }, - { 0x1a, 0xe7, 0x00 }, - { 0x1b, 0x26, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x19, 0x00 } - }, - { - { 0, 0, 0 } - }, - { - { 0x16, 0xcf, 0x00 }, - { 0x18, 0x00, 0x00 }, - { 0x1a, 0xe7, 0x00 }, - { 0x1b, 0x26, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x19, 0x00 }, - }, - { - { 0, 0, 0 } - }, - { - { 0x16, 0xcf, 0x00 }, - { 0x18, 0x00, 0x00 }, - { 0x1a, 0xe7, 0x00 }, - { 0x1b, 0x26, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x1e, 0x00 } - }, - { - { 0x16, 0xd1, 0x00 }, - { 0x18, 0x00, 0x00 }, - { 0x1a, 0xe6, 0x00 }, - { 0x1b, 0x11, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x26, 0x00 } - }, - { - { 0x18, 0x00, 0x00 }, - { 0x1a, 0xe0, 0x00 }, - { 0x1b, 0x26, 0x00 }, - { 0x1c, 0xff, 0x00 }, - { 0x1d, 0x1c, 0x00 }, - { 0x1e, 0x30, 0x00 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 } - }, - { - { 0, 0, 0 } - } - } +static const unsigned char barco_p1[2][9][7][3] = +{ + { + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x1e, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x16, 0x00 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 }, + { 0, 0, 0 } + }, + { + { 0, 0, 0 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x1e, 0x00 }, + { 0, 0, 0 } + }, + { + { 0x16, 0xd1, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x11, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x26, 0x00 } + }, + { + { 0x16, 0xd1, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x30, 0x00 }, + { 0, 0, 0 } + }, + { + { 0x16, 0x00, 0x00 }, + { 0x17, 0xa0, 0x00 }, + { 0x1a, 0xa0, 0x00 }, + { 0x1b, 0x2a, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0, 0, 0 } + }, + { + { 0x16, 0x00, 0x00 }, + { 0x17, 0xaa, 0x00 }, + { 0x1a, 0xa0, 0x00 }, + { 0x1b, 0x2a, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0, 0, 0 } + } + }, + { + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 } + }, + { + { 0, 0, 0 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x19, 0x00 }, + }, + { + { 0, 0, 0 } + }, + { + { 0x16, 0xcf, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe7, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x1e, 0x00 } + }, + { + { 0x16, 0xd1, 0x00 }, + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe6, 0x00 }, + { 0x1b, 0x11, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x26, 0x00 } + }, + { + { 0x18, 0x00, 0x00 }, + { 0x1a, 0xe0, 0x00 }, + { 0x1b, 0x26, 0x00 }, + { 0x1c, 0xff, 0x00 }, + { 0x1d, 0x1c, 0x00 }, + { 0x1e, 0x30, 0x00 }, + { 0, 0, 0 } + }, + { + { 0, 0, 0 } + }, + { + { 0, 0, 0 } + } + } }; diff --git a/drivers/video/sis/oem310.h b/drivers/video/sis/oem310.h index 2b7db916b7e7e..8fce56e4482c0 100644 --- a/drivers/video/sis/oem310.h +++ b/drivers/video/sis/oem310.h @@ -1,9 +1,9 @@ /* $XFree86$ */ /* $XdotOrg$ */ /* - * OEM Data for 315/330 series + * OEM Data for 315/330/340 series * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -50,206 +50,206 @@ * */ -static const UCHAR SiS310_LCDDelayCompensation_301[] = /* 301 */ +static const unsigned char SiS310_LCDDelayCompensation_301[] = /* 301 */ { - 0x00,0x00,0x00, /* 800x600 */ - 0x0b,0x0b,0x0b, /* 1024x768 */ - 0x08,0x08,0x08, /* 1280x1024 */ - 0x00,0x00,0x00, /* 640x480 (unknown) */ - 0x00,0x00,0x00, /* 1024x600 (unknown) */ - 0x00,0x00,0x00, /* 1152x864 (unknown) */ - 0x08,0x08,0x08, /* 1280x960 (guessed) */ - 0x00,0x00,0x00, /* 1152x768 (unknown) */ - 0x08,0x08,0x08, /* 1400x1050 */ - 0x08,0x08,0x08, /* 1280x768 (guessed) */ - 0x00,0x00,0x00, /* 1600x1200 */ - 0x00,0x00,0x00, /* 320x480 (unknown) */ - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00 + 0x00,0x00,0x00, /* 800x600 */ + 0x0b,0x0b,0x0b, /* 1024x768 */ + 0x08,0x08,0x08, /* 1280x1024 */ + 0x00,0x00,0x00, /* 640x480 (unknown) */ + 0x00,0x00,0x00, /* 1024x600 (unknown) */ + 0x00,0x00,0x00, /* 1152x864 (unknown) */ + 0x08,0x08,0x08, /* 1280x960 (guessed) */ + 0x00,0x00,0x00, /* 1152x768 (unknown) */ + 0x08,0x08,0x08, /* 1400x1050 */ + 0x08,0x08,0x08, /* 1280x768 (guessed) */ + 0x00,0x00,0x00, /* 1600x1200 */ + 0x00,0x00,0x00, /* 320x480 (unknown) */ + 0x00,0x00,0x00, + 0x00,0x00,0x00, + 0x00,0x00,0x00 }; /* This is contained in 650+301B BIOSes, but it is wrong - so we don't use it */ -static const UCHAR SiS310_LCDDelayCompensation_650301LV[] = /* 650 + 30xLV */ +static const unsigned char SiS310_LCDDelayCompensation_650301LV[] = /* 650 + 30xLV */ { - 0x01,0x01,0x01, /* 800x600 */ - 0x01,0x01,0x01, /* 1024x768 */ - 0x01,0x01,0x01, /* 1280x1024 */ - 0x01,0x01,0x01, /* 640x480 (unknown) */ - 0x01,0x01,0x01, /* 1024x600 (unknown) */ - 0x01,0x01,0x01, /* 1152x864 (unknown) */ - 0x01,0x01,0x01, /* 1280x960 (guessed) */ - 0x01,0x01,0x01, /* 1152x768 (unknown) */ - 0x01,0x01,0x01, /* 1400x1050 */ - 0x01,0x01,0x01, /* 1280x768 (guessed) */ - 0x01,0x01,0x01, /* 1600x1200 */ - 0x02,0x02,0x02, - 0x02,0x02,0x02, - 0x02,0x02,0x02, - 0x02,0x02,0x02 + 0x01,0x01,0x01, /* 800x600 */ + 0x01,0x01,0x01, /* 1024x768 */ + 0x01,0x01,0x01, /* 1280x1024 */ + 0x01,0x01,0x01, /* 640x480 (unknown) */ + 0x01,0x01,0x01, /* 1024x600 (unknown) */ + 0x01,0x01,0x01, /* 1152x864 (unknown) */ + 0x01,0x01,0x01, /* 1280x960 (guessed) */ + 0x01,0x01,0x01, /* 1152x768 (unknown) */ + 0x01,0x01,0x01, /* 1400x1050 */ + 0x01,0x01,0x01, /* 1280x768 (guessed) */ + 0x01,0x01,0x01, /* 1600x1200 */ + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02 }; -static const UCHAR SiS310_LCDDelayCompensation_651301LV[] = /* M650/651 301LV */ +static const unsigned char SiS310_LCDDelayCompensation_651301LV[] = /* M650/651 301LV */ { - 0x33,0x33,0x33, /* 800x600 (guessed) - new: PanelType, not PanelRes ! */ - 0x33,0x33,0x33, /* 1024x768 */ - 0x33,0x33,0x33, /* 1280x1024 */ - 0x33,0x33,0x33, /* 640x480 (unknown) */ - 0x33,0x33,0x33, /* 1024x600 (unknown) */ - 0x33,0x33,0x33, /* 1152x864 (unknown) */ - 0x33,0x33,0x33, /* 1280x960 (guessed) */ - 0x33,0x33,0x33, /* 1152x768 (unknown) */ - 0x33,0x33,0x33, /* 1400x1050 */ - 0x33,0x33,0x33, /* 1280x768 (guessed) */ - 0x33,0x33,0x33, /* 1600x1200 */ - 0x33,0x33,0x33, - 0x33,0x33,0x33, - 0x33,0x33,0x33, - 0x33,0x33,0x33 + 0x33,0x33,0x33, /* 800x600 (guessed) - new: PanelType, not PanelRes ! */ + 0x33,0x33,0x33, /* 1024x768 */ + 0x33,0x33,0x33, /* 1280x1024 */ + 0x33,0x33,0x33, /* 640x480 (unknown) */ + 0x33,0x33,0x33, /* 1024x600 (unknown) */ + 0x33,0x33,0x33, /* 1152x864 (unknown) */ + 0x33,0x33,0x33, /* 1280x960 (guessed) */ + 0x33,0x33,0x33, /* 1152x768 (unknown) */ + 0x33,0x33,0x33, /* 1400x1050 */ + 0x33,0x33,0x33, /* 1280x768 (guessed) */ + 0x33,0x33,0x33, /* 1600x1200 */ + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33 }; -static const UCHAR SiS310_LCDDelayCompensation_651302LV[] = /* M650/651 302LV */ +static const unsigned char SiS310_LCDDelayCompensation_651302LV[] = /* M650/651 302LV */ { - 0x33,0x33,0x33, /* 800x600 (guessed) */ - 0x33,0x33,0x33, /* 1024x768 */ - 0x33,0x33,0x33, /* 1280x1024 */ - 0x33,0x33,0x33, /* 640x480 (unknown) */ - 0x33,0x33,0x33, /* 1024x600 (unknown) */ - 0x33,0x33,0x33, /* 1152x864 (unknown) */ - 0x33,0x33,0x33, /* 1280x960 (guessed) */ - 0x33,0x33,0x33, /* 1152x768 (unknown) */ - 0x33,0x33,0x33, /* 1400x1050 */ - 0x33,0x33,0x33, /* 1280x768 (guessed) */ - 0x33,0x33,0x33, /* 1600x1200 */ - 0x33,0x33,0x33, - 0x33,0x33,0x33, - 0x33,0x33,0x33, - 0x33,0x33,0x33 + 0x33,0x33,0x33, /* 800x600 (guessed) */ + 0x33,0x33,0x33, /* 1024x768 */ + 0x33,0x33,0x33, /* 1280x1024 */ + 0x33,0x33,0x33, /* 640x480 (unknown) */ + 0x33,0x33,0x33, /* 1024x600 (unknown) */ + 0x33,0x33,0x33, /* 1152x864 (unknown) */ + 0x33,0x33,0x33, /* 1280x960 (guessed) */ + 0x33,0x33,0x33, /* 1152x768 (unknown) */ + 0x33,0x33,0x33, /* 1400x1050 */ + 0x33,0x33,0x33, /* 1280x768 (guessed) */ + 0x33,0x33,0x33, /* 1600x1200 */ + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33, + 0x33,0x33,0x33 }; -static const UCHAR SiS310_LCDDelayCompensation_3xx301B[] = /* 30xB */ +static const unsigned char SiS310_LCDDelayCompensation_3xx301B[] = /* 30xB */ { - 0x01,0x01,0x01, /* 800x600 */ - 0x0C,0x0C,0x0C, /* 1024x768 */ - 0x0C,0x0C,0x0C, /* 1280x1024 */ - 0x08,0x08,0x08, /* 640x480 */ - 0x0C,0x0C,0x0C, /* 1024x600 (guessed) */ - 0x0C,0x0C,0x0C, /* 1152x864 (guessed) */ - 0x0C,0x0C,0x0C, /* 1280x960 (guessed) */ - 0x0C,0x0C,0x0C, /* 1152x768 (guessed) */ - 0x0C,0x0C,0x0C, /* 1400x1050 (guessed) */ - 0x0C,0x0C,0x0C, /* 1280x768 (guessed) */ - 0x0C,0x0C,0x0C, /* 1600x1200 (guessed) */ - 0x02,0x02,0x02, - 0x02,0x02,0x02, - 0x02,0x02,0x02, - 0x02,0x02,0x02 + 0x01,0x01,0x01, /* 800x600 */ + 0x0C,0x0C,0x0C, /* 1024x768 */ + 0x0C,0x0C,0x0C, /* 1280x1024 */ + 0x08,0x08,0x08, /* 640x480 */ + 0x0C,0x0C,0x0C, /* 1024x600 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x864 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x960 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1400x1050 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1600x1200 (guessed) */ + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02 }; -static const UCHAR SiS310_LCDDelayCompensation_3xx301LV[] = /* 315+30xLV */ +static const unsigned char SiS310_LCDDelayCompensation_3xx301LV[] = /* 315+30xLV */ { - 0x01,0x01,0x01, /* 800x600 */ - 0x04,0x04,0x04, /* 1024x768 (A531/BIOS 1.14.05f: 4 - works with 6 */ - 0x0C,0x0C,0x0C, /* 1280x1024 */ - 0x08,0x08,0x08, /* 640x480 */ - 0x0C,0x0C,0x0C, /* 1024x600 (guessed) */ - 0x0C,0x0C,0x0C, /* 1152x864 (guessed) */ - 0x0C,0x0C,0x0C, /* 1280x960 (guessed) */ - 0x0C,0x0C,0x0C, /* 1152x768 (guessed) */ - 0x0C,0x0C,0x0C, /* 1400x1050 (guessed) */ - 0x0C,0x0C,0x0C, /* 1280x768 (guessed) */ - 0x0C,0x0C,0x0C, /* 1600x1200 (guessed) */ - 0x02,0x02,0x02, - 0x02,0x02,0x02, - 0x02,0x02,0x02, - 0x02,0x02,0x02 + 0x01,0x01,0x01, /* 800x600 */ + 0x04,0x04,0x04, /* 1024x768 (A531/BIOS 1.14.05f: 4 - works with 6 */ + 0x0C,0x0C,0x0C, /* 1280x1024 */ + 0x08,0x08,0x08, /* 640x480 */ + 0x0C,0x0C,0x0C, /* 1024x600 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x864 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x960 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1400x1050 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1600x1200 (guessed) */ + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02 }; -static const UCHAR SiS310_TVDelayCompensation_301[] = /* 301 */ +static const unsigned char SiS310_TVDelayCompensation_301[] = /* 301 */ { - 0x02,0x02, /* NTSC Enhanced, Standard */ - 0x02,0x02, /* PAL */ - 0x08,0x0b /* HiVision */ + 0x02,0x02, /* NTSC Enhanced, Standard */ + 0x02,0x02, /* PAL */ + 0x08,0x0b /* HiVision */ }; -static const UCHAR SiS310_TVDelayCompensation_301B[] = /* 30xB, 30xLV */ +static const unsigned char SiS310_TVDelayCompensation_301B[] = /* 30xB, 30xLV */ { - 0x03,0x03, - 0x03,0x03, - 0x03,0x03 + 0x03,0x03, + 0x03,0x03, + 0x03,0x03 }; -static const UCHAR SiS310_TVDelayCompensation_740301B[] = /* 740 + 30xB (30xLV?) */ +static const unsigned char SiS310_TVDelayCompensation_740301B[] = /* 740 + 30xB (30xLV?) */ { - 0x05,0x05, - 0x05,0x05, - 0x05,0x05 + 0x05,0x05, + 0x05,0x05, + 0x05,0x05 }; -static const UCHAR SiS310_TVDelayCompensation_651301LV[] = /* M650, 651, 301LV */ +static const unsigned char SiS310_TVDelayCompensation_651301LV[] = /* M650, 651, 301LV */ { - 0x33,0x33, - 0x33,0x33, - 0x33,0x33 + 0x33,0x33, + 0x33,0x33, + 0x33,0x33 }; -static const UCHAR SiS310_TVDelayCompensation_651302LV[] = /* M650, 651, 302LV */ +static const unsigned char SiS310_TVDelayCompensation_651302LV[] = /* M650, 651, 302LV */ { - 0x33,0x33, - 0x33,0x33, - 0x33,0x33 + 0x33,0x33, + 0x33,0x33, + 0x33,0x33 }; -static const UCHAR SiS_TVDelay661_301[] = /* 661, 301 */ +static const unsigned char SiS_TVDelay661_301[] = /* 661, 301 */ { - 0x44,0x44, - 0x44,0x44, - 0x00,0x00, - 0x44,0x44, - 0x44,0x44, - 0x44,0x44 + 0x44,0x44, + 0x44,0x44, + 0x00,0x00, + 0x44,0x44, + 0x44,0x44, + 0x44,0x44 }; -static const UCHAR SiS_TVDelay661_301B[] = /* 661, 301B et al */ +static const unsigned char SiS_TVDelay661_301B[] = /* 661, 301B et al */ { - 0x44,0x44, - 0x44,0x44, - 0x00,0x00, - 0x44,0x44, - 0x44,0x44, - 0x44,0x44 + 0x44,0x44, + 0x44,0x44, + 0x00,0x00, + 0x44,0x44, + 0x44,0x44, + 0x44,0x44 }; -static const UCHAR SiS310_TVDelayCompensation_LVDS[] = /* LVDS */ +static const unsigned char SiS310_TVDelayCompensation_LVDS[] = /* LVDS */ { - 0x0a,0x0a, - 0x0a,0x0a, - 0x0a,0x0a + 0x0a,0x0a, + 0x0a,0x0a, + 0x0a,0x0a }; -static const UCHAR SiS310_TVAntiFlick1[6][2] = +static const unsigned char SiS310_TVAntiFlick1[6][2] = { - {0x4,0x0}, - {0x4,0x8}, - {0x0,0x0}, - {0x0,0x0}, - {0x0,0x0}, - {0x0,0x0} + {0x4,0x0}, + {0x4,0x8}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0} }; -static const UCHAR SiS310_TVEdge1[6][2] = +static const unsigned char SiS310_TVEdge1[6][2] = { - {0x0,0x4}, - {0x0,0x4}, - {0x0,0x0}, - {0x0,0x0}, - {0x0,0x0}, - {0x0,0x0} + {0x0,0x4}, + {0x0,0x4}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0}, + {0x0,0x0} }; -static const UCHAR SiS310_TVYFilter1[5][8][4] = +static const unsigned char SiS310_TVYFilter1[5][8][4] = { - { + { {0x00,0xf4,0x10,0x38}, /* NTSC */ {0x00,0xf4,0x10,0x38}, {0xeb,0x04,0x25,0x18}, @@ -258,8 +258,8 @@ static const UCHAR SiS310_TVYFilter1[5][8][4] = {0xeb,0x04,0x25,0x18}, {0xee,0x0c,0x22,0x08}, {0xeb,0x15,0x25,0xf6} - }, - { + }, + { {0x00,0xf4,0x10,0x38}, /* PAL */ {0x00,0xf4,0x10,0x38}, {0xf1,0xf7,0x1f,0x32}, @@ -268,8 +268,8 @@ static const UCHAR SiS310_TVYFilter1[5][8][4] = {0xf1,0xf7,0x1f,0x32}, {0xf3,0x00,0x1d,0x20}, {0xfc,0xfb,0x14,0x2a} - }, - { + }, + { {0x00,0x00,0x00,0x00}, /* HiVision */ {0x00,0xf4,0x10,0x38}, {0x00,0xf4,0x10,0x38}, @@ -278,9 +278,9 @@ static const UCHAR SiS310_TVYFilter1[5][8][4] = {0x00,0xf4,0x10,0x38}, {0xeb,0x04,0x25,0x18}, {0xee,0x0c,0x22,0x08} - }, - { - {0x00,0xf4,0x10,0x38}, /* PAL-M */ + }, + { + {0x00,0xf4,0x10,0x38}, /* PAL-M */ {0x00,0xf4,0x10,0x38}, {0xeb,0x04,0x10,0x18}, {0xf7,0x06,0x19,0x14}, @@ -288,9 +288,9 @@ static const UCHAR SiS310_TVYFilter1[5][8][4] = {0xeb,0x04,0x25,0x18}, {0xeb,0x04,0x25,0x18}, {0xeb,0x15,0x25,0xf6} - }, - { - {0x00,0xf4,0x10,0x38}, /* PAL-N */ + }, + { + {0x00,0xf4,0x10,0x38}, /* PAL-N */ {0x00,0xf4,0x10,0x38}, {0xeb,0x04,0x10,0x18}, {0xf7,0x06,0x19,0x14}, @@ -298,12 +298,12 @@ static const UCHAR SiS310_TVYFilter1[5][8][4] = {0xeb,0x04,0x25,0x18}, {0xeb,0x04,0x25,0x18}, {0xeb,0x15,0x25,0xf6} - } + } }; -static const UCHAR SiS310_TVYFilter2[5][9][7] = +static const unsigned char SiS310_TVYFilter2[5][9][7] = { - { + { {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* NTSC */ {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, @@ -313,8 +313,8 @@ static const UCHAR SiS310_TVYFilter2[5][9][7] = {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} - }, - { + }, + { {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL */ {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, @@ -324,8 +324,8 @@ static const UCHAR SiS310_TVYFilter2[5][9][7] = {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} - }, - { + }, + { {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, /* HiVision */ {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, @@ -335,9 +335,9 @@ static const UCHAR SiS310_TVYFilter2[5][9][7] = {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}, {0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22} - }, - { - {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL-M */ + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL-M */ {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, @@ -346,9 +346,9 @@ static const UCHAR SiS310_TVYFilter2[5][9][7] = {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} - }, - { - {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL-N */ + }, + { + {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, /* PAL-N */ {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46}, {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, @@ -357,58 +357,39 @@ static const UCHAR SiS310_TVYFilter2[5][9][7] = {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C}, {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38}, {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28} - } + } }; -static const UCHAR SiS310_TVPhaseIncr1[3][2][4] = +static const unsigned char SiS310_TVPhaseIncr1[3][2][4] = { - { + { {0x21,0xed,0xba,0x08}, {0x21,0xed,0xba,0x08} - }, - { + }, + { {0x2a,0x05,0xe3,0x00}, {0x2a,0x05,0xe3,0x00} - }, - { + }, + { {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00} - } + } }; -static const UCHAR SiS310_TVPhaseIncr2[3][2][4] = +static const unsigned char SiS310_TVPhaseIncr2[3][2][4] = { - { + { {0x21,0xf0,0x7b,0xd6}, {0x21,0xf0,0x7b,0xd6} - }, - { + }, + { {0x2a,0x0a,0x41,0xe9}, {0x2a,0x0a,0x41,0xe9} - }, - { + }, + { {0x2a,0x05,0xd3,0x00}, {0x2a,0x05,0xd3,0x00} - } -}; - -static const UCHAR SiS661_TVPhase[] = { - 0x21,0xED,0xBA,0x08, - 0x2A,0x05,0xE3,0x00, - 0x21,0xE4,0x2E,0x9B, - 0x21,0xF4,0x3E,0xBA, - 0x1E,0x8B,0xA2,0xA7, - 0x1E,0x83,0x0A,0xE0, - 0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00, - 0x21,0xF0,0x7B,0xD6, - 0x2A,0x09,0x86,0xE9, - 0x21,0xE6,0xEF,0xA4, - 0x21,0xF6,0x94,0x46, - 0x1E,0x8B,0xA2,0xA7, - 0x1E,0x83,0x0A,0xE0, - 0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00 + } }; /**************************************************************/ @@ -417,7 +398,7 @@ static const UCHAR SiS661_TVPhase[] = { /* Inventec / Compaq Presario 3045US, 3017 */ -static const SiS_LCDDataStruct SiS310_ExtCompaq1280x1024Data[] = +static const struct SiS_LCDData SiS310_ExtCompaq1280x1024Data[] = { { 211, 60,1024, 501,1688,1066}, { 211, 60,1024, 508,1688,1066}, @@ -431,17 +412,17 @@ static const SiS_LCDDataStruct SiS310_ExtCompaq1280x1024Data[] = /* Asus A2xxxH _2 */ -static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Asus1024x768_3[] = +static const struct SiS_Part2PortTbl SiS310_CRT2Part2_Asus1024x768_3[] = { - {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x2c,0x13,0x9a,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x38,0x13,0x16,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, - {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} + {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x2c,0x13,0x9a,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, + {{0x38,0x13,0x16,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} }; diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h index 15939b0577131..841ca3190cd4d 100644 --- a/drivers/video/sis/osdef.h +++ b/drivers/video/sis/osdef.h @@ -3,7 +3,7 @@ /* * OS depending defines * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -55,8 +55,11 @@ #define _SIS_OSDEF_H_ /* The choices are: */ -#define LINUX_KERNEL /* Linux kernel framebuffer */ -/* #define LINUX_XF86 */ /* XFree86/X.org */ +#define SIS_LINUX_KERNEL /* Linux kernel framebuffer */ +#undef SIS_XORG_XF86 /* XFree86/X.org */ + +#undef SIS_LINUX_KERNEL_24 +#undef SIS_LINUX_KERNEL_26 #ifdef OutPortByte #undef OutPortByte @@ -86,8 +89,9 @@ /* LINUX KERNEL */ /**********************************************************************/ -#ifdef LINUX_KERNEL +#ifdef SIS_LINUX_KERNEL #include <linux/config.h> +#include <linux/version.h> #ifdef CONFIG_FB_SIS_300 #define SIS300 @@ -97,6 +101,12 @@ #define SIS315H #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#define SIS_LINUX_KERNEL_26 +#else +#define SIS_LINUX_KERNEL_24 +#endif + #if !defined(SIS300) && !defined(SIS315H) #warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set #warning sisfb will not work! @@ -109,13 +119,15 @@ #define InPortWord(p) inw((SISIOADDRESS)(p)) #define InPortLong(p) inl((SISIOADDRESS)(p)) #define SiS_SetMemory(MemoryAddress,MemorySize,value) memset_io(MemoryAddress, value, MemorySize) -#endif + +#endif /* LINUX_KERNEL */ /**********************************************************************/ /* XFree86/X.org */ /**********************************************************************/ -#ifdef LINUX_XF86 +#ifdef SIS_XORG_XF86 + #define SIS300 #define SIS315H @@ -126,6 +138,7 @@ #define InPortWord(p) inSISREGW((IOADDRESS)(p)) #define InPortLong(p) inSISREGL((IOADDRESS)(p)) #define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize) -#endif + +#endif /* XF86 */ #endif /* _OSDEF_H_ */ diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h index d0103c162e43b..0b6e625d73316 100644 --- a/drivers/video/sis/sis.h +++ b/drivers/video/sis/sis.h @@ -1,8 +1,10 @@ /* - * SiS 300/630/730/540/315/550/[M]650/651/[M]661[FM]X/740/[M]741[GX]/330/[M]760[GX] + * SiS 300/540/630[S]/730[S], + * SiS 315[E|PRO]/550/[M]65x/[M]661[F|M]X/740/[M]741[GX]/330/[M]76x[GX], + * XGI V3XT/V5/V8, Z7 * frame buffer driver for Linux kernels >=2.4.14 and >=2.6.3 * - * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria. + * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria. * * 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 @@ -19,8 +21,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ -#ifndef _SIS_H -#define _SIS_H +#ifndef _SIS_H_ +#define _SIS_H_ #include <linux/config.h> #include <linux/version.h> @@ -35,26 +37,37 @@ #include "vgatypes.h" #include "vstruct.h" -#define VER_MAJOR 1 -#define VER_MINOR 7 -#define VER_LEVEL 17 - -#undef SIS_CONFIG_COMPAT +#define VER_MAJOR 1 +#define VER_MINOR 8 +#define VER_LEVEL 9 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) #include <linux/spinlock.h> +#define SIS_PCI_GET_CLASS(a, b) pci_get_class(a, b) +#define SIS_PCI_GET_DEVICE(a,b,c) pci_get_device(a,b,c) +#define SIS_PCI_GET_SLOT(a,b) pci_get_slot(a,b) +#define SIS_PCI_PUT_DEVICE(a) pci_dev_put(a) #ifdef CONFIG_COMPAT +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10) #include <linux/ioctl32.h> -#define SIS_CONFIG_COMPAT -#endif -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19) -#ifdef __x86_64__ -/* Shouldn't we check for CONFIG_IA32_EMULATION here? */ +#define SIS_OLD_CONFIG_COMPAT +#else +#include <linux/smp_lock.h> +#define SIS_NEW_CONFIG_COMPAT +#endif +#endif /* CONFIG_COMPAT */ +#else /* 2.4 */ +#define SIS_PCI_GET_CLASS(a, b) pci_find_class(a, b) +#define SIS_PCI_GET_DEVICE(a,b,c) pci_find_device(a,b,c) +#define SIS_PCI_GET_SLOT(a,b) pci_find_slot(a,b) +#define SIS_PCI_PUT_DEVICE(a) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19) +#ifdef __x86_64__ /* Shouldn't we check for CONFIG_IA32_EMULATION here? */ #include <asm/ioctl32.h> -#define SIS_CONFIG_COMPAT +#define SIS_OLD_CONFIG_COMPAT #endif #endif - +#endif /* 2.4 */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) #define SIS_IOTYPE1 void __iomem #define SIS_IOTYPE2 __iomem @@ -79,228 +92,312 @@ /* To be included in pci_ids.h */ #ifndef PCI_DEVICE_ID_SI_650_VGA -#define PCI_DEVICE_ID_SI_650_VGA 0x6325 +#define PCI_DEVICE_ID_SI_650_VGA 0x6325 #endif #ifndef PCI_DEVICE_ID_SI_650 -#define PCI_DEVICE_ID_SI_650 0x0650 +#define PCI_DEVICE_ID_SI_650 0x0650 #endif #ifndef PCI_DEVICE_ID_SI_651 -#define PCI_DEVICE_ID_SI_651 0x0651 +#define PCI_DEVICE_ID_SI_651 0x0651 #endif #ifndef PCI_DEVICE_ID_SI_740 -#define PCI_DEVICE_ID_SI_740 0x0740 +#define PCI_DEVICE_ID_SI_740 0x0740 #endif #ifndef PCI_DEVICE_ID_SI_330 -#define PCI_DEVICE_ID_SI_330 0x0330 +#define PCI_DEVICE_ID_SI_330 0x0330 #endif #ifndef PCI_DEVICE_ID_SI_660_VGA -#define PCI_DEVICE_ID_SI_660_VGA 0x6330 +#define PCI_DEVICE_ID_SI_660_VGA 0x6330 #endif #ifndef PCI_DEVICE_ID_SI_661 -#define PCI_DEVICE_ID_SI_661 0x0661 +#define PCI_DEVICE_ID_SI_661 0x0661 #endif #ifndef PCI_DEVICE_ID_SI_741 -#define PCI_DEVICE_ID_SI_741 0x0741 +#define PCI_DEVICE_ID_SI_741 0x0741 #endif #ifndef PCI_DEVICE_ID_SI_660 -#define PCI_DEVICE_ID_SI_660 0x0660 +#define PCI_DEVICE_ID_SI_660 0x0660 #endif #ifndef PCI_DEVICE_ID_SI_760 -#define PCI_DEVICE_ID_SI_760 0x0760 +#define PCI_DEVICE_ID_SI_760 0x0760 +#endif +#ifndef PCI_DEVICE_ID_SI_761 +#define PCI_DEVICE_ID_SI_761 0x0761 +#endif + +#ifndef PCI_VENDOR_ID_XGI +#define PCI_VENDOR_ID_XGI 0x18ca +#endif + +#ifndef PCI_DEVICE_ID_XGI_20 +#define PCI_DEVICE_ID_XGI_20 0x0020 +#endif + +#ifndef PCI_DEVICE_ID_XGI_40 +#define PCI_DEVICE_ID_XGI_40 0x0040 #endif /* To be included in fb.h */ #ifndef FB_ACCEL_SIS_GLAMOUR_2 -#define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 65x, 740, 661, 741 */ +#define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 65x, 740, 661, 741 */ #endif #ifndef FB_ACCEL_SIS_XABRE -#define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre"), 760 */ +#define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre"), 76x */ +#endif +#ifndef FB_ACCEL_XGI_VOLARI_V +#define FB_ACCEL_XGI_VOLARI_V 47 /* XGI Volari Vx (V3XT, V5, V8) */ +#endif +#ifndef FB_ACCEL_XGI_VOLARI_Z +#define FB_ACCEL_XGI_VOLARI_Z 48 /* XGI Volari Z7 */ #endif - -#define MAX_ROM_SCAN 0x10000 /* ivideo->caps */ -#define HW_CURSOR_CAP 0x80 -#define TURBO_QUEUE_CAP 0x40 -#define AGP_CMD_QUEUE_CAP 0x20 -#define VM_CMD_QUEUE_CAP 0x10 -#define MMIO_CMD_QUEUE_CAP 0x08 +#define HW_CURSOR_CAP 0x80 +#define TURBO_QUEUE_CAP 0x40 +#define AGP_CMD_QUEUE_CAP 0x20 +#define VM_CMD_QUEUE_CAP 0x10 +#define MMIO_CMD_QUEUE_CAP 0x08 /* For 300 series */ -#define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */ -#define HW_CURSOR_AREA_SIZE_300 0x1000 /* 4K */ +#define TURBO_QUEUE_AREA_SIZE (512 * 1024) /* 512K */ +#define HW_CURSOR_AREA_SIZE_300 4096 /* 4K */ /* For 315/Xabre series */ -#define COMMAND_QUEUE_AREA_SIZE 0x80000 /* 512K */ -#define COMMAND_QUEUE_THRESHOLD 0x1F -#define HW_CURSOR_AREA_SIZE_315 0x4000 /* 16K */ - -#define SIS_OH_ALLOC_SIZE 4000 -#define SENTINEL 0x7fffffff - -#define SEQ_ADR 0x14 -#define SEQ_DATA 0x15 -#define DAC_ADR 0x18 -#define DAC_DATA 0x19 -#define CRTC_ADR 0x24 -#define CRTC_DATA 0x25 -#define DAC2_ADR (0x16-0x30) -#define DAC2_DATA (0x17-0x30) -#define VB_PART1_ADR (0x04-0x30) -#define VB_PART1_DATA (0x05-0x30) -#define VB_PART2_ADR (0x10-0x30) -#define VB_PART2_DATA (0x11-0x30) -#define VB_PART3_ADR (0x12-0x30) -#define VB_PART3_DATA (0x13-0x30) -#define VB_PART4_ADR (0x14-0x30) -#define VB_PART4_DATA (0x15-0x30) - -#define SISSR ivideo->SiS_Pr.SiS_P3c4 -#define SISCR ivideo->SiS_Pr.SiS_P3d4 -#define SISDACA ivideo->SiS_Pr.SiS_P3c8 -#define SISDACD ivideo->SiS_Pr.SiS_P3c9 -#define SISPART1 ivideo->SiS_Pr.SiS_Part1Port -#define SISPART2 ivideo->SiS_Pr.SiS_Part2Port -#define SISPART3 ivideo->SiS_Pr.SiS_Part3Port -#define SISPART4 ivideo->SiS_Pr.SiS_Part4Port -#define SISPART5 ivideo->SiS_Pr.SiS_Part5Port -#define SISDAC2A SISPART5 -#define SISDAC2D (SISPART5 + 1) -#define SISMISCR (ivideo->SiS_Pr.RelIO + 0x1c) -#define SISMISCW ivideo->SiS_Pr.SiS_P3c2 -#define SISINPSTAT (ivideo->SiS_Pr.RelIO + 0x2a) -#define SISPEL ivideo->SiS_Pr.SiS_P3c6 - -#define IND_SIS_PASSWORD 0x05 /* SRs */ -#define IND_SIS_COLOR_MODE 0x06 -#define IND_SIS_RAMDAC_CONTROL 0x07 -#define IND_SIS_DRAM_SIZE 0x14 -#define IND_SIS_MODULE_ENABLE 0x1E -#define IND_SIS_PCI_ADDRESS_SET 0x20 -#define IND_SIS_TURBOQUEUE_ADR 0x26 -#define IND_SIS_TURBOQUEUE_SET 0x27 -#define IND_SIS_POWER_ON_TRAP 0x38 -#define IND_SIS_POWER_ON_TRAP2 0x39 -#define IND_SIS_CMDQUEUE_SET 0x26 -#define IND_SIS_CMDQUEUE_THRESHOLD 0x27 - -#define IND_SIS_AGP_IO_PAD 0x48 - -#define SIS_CRT2_WENABLE_300 0x24 /* Part1 */ -#define SIS_CRT2_WENABLE_315 0x2F - -#define SIS_PASSWORD 0x86 /* SR05 */ - -#define SIS_INTERLACED_MODE 0x20 /* SR06 */ -#define SIS_8BPP_COLOR_MODE 0x0 -#define SIS_15BPP_COLOR_MODE 0x1 -#define SIS_16BPP_COLOR_MODE 0x2 -#define SIS_32BPP_COLOR_MODE 0x4 - -#define SIS_ENABLE_2D 0x40 /* SR1E */ - -#define SIS_MEM_MAP_IO_ENABLE 0x01 /* SR20 */ -#define SIS_PCI_ADDR_ENABLE 0x80 - -#define SIS_AGP_CMDQUEUE_ENABLE 0x80 /* 315/330 series SR26 */ -#define SIS_VRAM_CMDQUEUE_ENABLE 0x40 -#define SIS_MMIO_CMD_ENABLE 0x20 -#define SIS_CMD_QUEUE_SIZE_512k 0x00 -#define SIS_CMD_QUEUE_SIZE_1M 0x04 -#define SIS_CMD_QUEUE_SIZE_2M 0x08 -#define SIS_CMD_QUEUE_SIZE_4M 0x0C -#define SIS_CMD_QUEUE_RESET 0x01 -#define SIS_CMD_AUTO_CORR 0x02 - -#define SIS_SIMULTANEOUS_VIEW_ENABLE 0x01 /* CR30 */ -#define SIS_MODE_SELECT_CRT2 0x02 -#define SIS_VB_OUTPUT_COMPOSITE 0x04 -#define SIS_VB_OUTPUT_SVIDEO 0x08 -#define SIS_VB_OUTPUT_SCART 0x10 -#define SIS_VB_OUTPUT_LCD 0x20 -#define SIS_VB_OUTPUT_CRT2 0x40 -#define SIS_VB_OUTPUT_HIVISION 0x80 - -#define SIS_VB_OUTPUT_DISABLE 0x20 /* CR31 */ -#define SIS_DRIVER_MODE 0x40 - -#define SIS_VB_COMPOSITE 0x01 /* CR32 */ -#define SIS_VB_SVIDEO 0x02 -#define SIS_VB_SCART 0x04 -#define SIS_VB_LCD 0x08 -#define SIS_VB_CRT2 0x10 -#define SIS_CRT1 0x20 -#define SIS_VB_HIVISION 0x40 -#define SIS_VB_YPBPR 0x80 -#define SIS_VB_TV (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | \ - SIS_VB_SCART | SIS_VB_HIVISION | SIS_VB_YPBPR) - -#define SIS_EXTERNAL_CHIP_MASK 0x0E /* CR37 (< SiS 660) */ -#define SIS_EXTERNAL_CHIP_SIS301 0x01 /* in CR37 << 1 ! */ -#define SIS_EXTERNAL_CHIP_LVDS 0x02 -#define SIS_EXTERNAL_CHIP_TRUMPION 0x03 -#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL 0x04 -#define SIS_EXTERNAL_CHIP_CHRONTEL 0x05 -#define SIS310_EXTERNAL_CHIP_LVDS 0x02 -#define SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03 - -#define SIS_AGP_2X 0x20 /* CR48 */ - -#define HW_DEVICE_EXTENSION SIS_HW_INFO -#define PHW_DEVICE_EXTENSION PSIS_HW_INFO +#define COMMAND_QUEUE_AREA_SIZE (512 * 1024) /* 512K */ +#define COMMAND_QUEUE_AREA_SIZE_Z7 (128 * 1024) /* 128k for XGI Z7 */ +#define HW_CURSOR_AREA_SIZE_315 16384 /* 16K */ +#define COMMAND_QUEUE_THRESHOLD 0x1F + +#define SIS_OH_ALLOC_SIZE 4000 +#define SENTINEL 0x7fffffff + +#define SEQ_ADR 0x14 +#define SEQ_DATA 0x15 +#define DAC_ADR 0x18 +#define DAC_DATA 0x19 +#define CRTC_ADR 0x24 +#define CRTC_DATA 0x25 +#define DAC2_ADR (0x16-0x30) +#define DAC2_DATA (0x17-0x30) +#define VB_PART1_ADR (0x04-0x30) +#define VB_PART1_DATA (0x05-0x30) +#define VB_PART2_ADR (0x10-0x30) +#define VB_PART2_DATA (0x11-0x30) +#define VB_PART3_ADR (0x12-0x30) +#define VB_PART3_DATA (0x13-0x30) +#define VB_PART4_ADR (0x14-0x30) +#define VB_PART4_DATA (0x15-0x30) + +#define SISSR ivideo->SiS_Pr.SiS_P3c4 +#define SISCR ivideo->SiS_Pr.SiS_P3d4 +#define SISDACA ivideo->SiS_Pr.SiS_P3c8 +#define SISDACD ivideo->SiS_Pr.SiS_P3c9 +#define SISPART1 ivideo->SiS_Pr.SiS_Part1Port +#define SISPART2 ivideo->SiS_Pr.SiS_Part2Port +#define SISPART3 ivideo->SiS_Pr.SiS_Part3Port +#define SISPART4 ivideo->SiS_Pr.SiS_Part4Port +#define SISPART5 ivideo->SiS_Pr.SiS_Part5Port +#define SISDAC2A SISPART5 +#define SISDAC2D (SISPART5 + 1) +#define SISMISCR (ivideo->SiS_Pr.RelIO + 0x1c) +#define SISMISCW ivideo->SiS_Pr.SiS_P3c2 +#define SISINPSTAT (ivideo->SiS_Pr.RelIO + 0x2a) +#define SISPEL ivideo->SiS_Pr.SiS_P3c6 +#define SISVGAENABLE (ivideo->SiS_Pr.RelIO + 0x13) +#define SISVID (ivideo->SiS_Pr.RelIO + 0x02 - 0x30) +#define SISCAP (ivideo->SiS_Pr.RelIO + 0x00 - 0x30) + +#define IND_SIS_PASSWORD 0x05 /* SRs */ +#define IND_SIS_COLOR_MODE 0x06 +#define IND_SIS_RAMDAC_CONTROL 0x07 +#define IND_SIS_DRAM_SIZE 0x14 +#define IND_SIS_MODULE_ENABLE 0x1E +#define IND_SIS_PCI_ADDRESS_SET 0x20 +#define IND_SIS_TURBOQUEUE_ADR 0x26 +#define IND_SIS_TURBOQUEUE_SET 0x27 +#define IND_SIS_POWER_ON_TRAP 0x38 +#define IND_SIS_POWER_ON_TRAP2 0x39 +#define IND_SIS_CMDQUEUE_SET 0x26 +#define IND_SIS_CMDQUEUE_THRESHOLD 0x27 + +#define IND_SIS_AGP_IO_PAD 0x48 + +#define SIS_CRT2_WENABLE_300 0x24 /* Part1 */ +#define SIS_CRT2_WENABLE_315 0x2F + +#define SIS_PASSWORD 0x86 /* SR05 */ + +#define SIS_INTERLACED_MODE 0x20 /* SR06 */ +#define SIS_8BPP_COLOR_MODE 0x0 +#define SIS_15BPP_COLOR_MODE 0x1 +#define SIS_16BPP_COLOR_MODE 0x2 +#define SIS_32BPP_COLOR_MODE 0x4 + +#define SIS_ENABLE_2D 0x40 /* SR1E */ + +#define SIS_MEM_MAP_IO_ENABLE 0x01 /* SR20 */ +#define SIS_PCI_ADDR_ENABLE 0x80 + +#define SIS_AGP_CMDQUEUE_ENABLE 0x80 /* 315/330/340 series SR26 */ +#define SIS_VRAM_CMDQUEUE_ENABLE 0x40 +#define SIS_MMIO_CMD_ENABLE 0x20 +#define SIS_CMD_QUEUE_SIZE_512k 0x00 +#define SIS_CMD_QUEUE_SIZE_1M 0x04 +#define SIS_CMD_QUEUE_SIZE_2M 0x08 +#define SIS_CMD_QUEUE_SIZE_4M 0x0C +#define SIS_CMD_QUEUE_RESET 0x01 +#define SIS_CMD_AUTO_CORR 0x02 + +#define SIS_CMD_QUEUE_SIZE_Z7_64k 0x00 /* XGI Z7 */ +#define SIS_CMD_QUEUE_SIZE_Z7_128k 0x04 + +#define SIS_SIMULTANEOUS_VIEW_ENABLE 0x01 /* CR30 */ +#define SIS_MODE_SELECT_CRT2 0x02 +#define SIS_VB_OUTPUT_COMPOSITE 0x04 +#define SIS_VB_OUTPUT_SVIDEO 0x08 +#define SIS_VB_OUTPUT_SCART 0x10 +#define SIS_VB_OUTPUT_LCD 0x20 +#define SIS_VB_OUTPUT_CRT2 0x40 +#define SIS_VB_OUTPUT_HIVISION 0x80 + +#define SIS_VB_OUTPUT_DISABLE 0x20 /* CR31 */ +#define SIS_DRIVER_MODE 0x40 + +#define SIS_VB_COMPOSITE 0x01 /* CR32 */ +#define SIS_VB_SVIDEO 0x02 +#define SIS_VB_SCART 0x04 +#define SIS_VB_LCD 0x08 +#define SIS_VB_CRT2 0x10 +#define SIS_CRT1 0x20 +#define SIS_VB_HIVISION 0x40 +#define SIS_VB_YPBPR 0x80 +#define SIS_VB_TV (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | \ + SIS_VB_SCART | SIS_VB_HIVISION | SIS_VB_YPBPR) + +#define SIS_EXTERNAL_CHIP_MASK 0x0E /* CR37 (< SiS 660) */ +#define SIS_EXTERNAL_CHIP_SIS301 0x01 /* in CR37 << 1 ! */ +#define SIS_EXTERNAL_CHIP_LVDS 0x02 +#define SIS_EXTERNAL_CHIP_TRUMPION 0x03 +#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL 0x04 +#define SIS_EXTERNAL_CHIP_CHRONTEL 0x05 +#define SIS310_EXTERNAL_CHIP_LVDS 0x02 +#define SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03 + +#define SIS_AGP_2X 0x20 /* CR48 */ + +/* vbflags, private entries (others in sisfb.h) */ +#define VB_CONEXANT 0x00000800 /* 661 series only */ +#define VB_TRUMPION VB_CONEXANT /* 300 series only */ +#define VB_302ELV 0x00004000 +#define VB_301 0x00100000 /* Video bridge type */ +#define VB_301B 0x00200000 +#define VB_302B 0x00400000 +#define VB_30xBDH 0x00800000 /* 30xB DH version (w/o LCD support) */ +#define VB_LVDS 0x01000000 +#define VB_CHRONTEL 0x02000000 +#define VB_301LV 0x04000000 +#define VB_302LV 0x08000000 +#define VB_301C 0x10000000 + +#define VB_SISBRIDGE (VB_301|VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV|VB_302ELV) +#define VB_VIDEOBRIDGE (VB_SISBRIDGE | VB_LVDS | VB_CHRONTEL | VB_CONEXANT) + +/* vbflags2 (static stuff only!) */ +#define VB2_SISUMC 0x00000001 +#define VB2_301 0x00000002 /* Video bridge type */ +#define VB2_301B 0x00000004 +#define VB2_301C 0x00000008 +#define VB2_307T 0x00000010 +#define VB2_302B 0x00000800 +#define VB2_301LV 0x00001000 +#define VB2_302LV 0x00002000 +#define VB2_302ELV 0x00004000 +#define VB2_307LV 0x00008000 +#define VB2_30xBDH 0x08000000 /* 30xB DH version (w/o LCD support) */ +#define VB2_CONEXANT 0x10000000 +#define VB2_TRUMPION 0x20000000 +#define VB2_LVDS 0x40000000 +#define VB2_CHRONTEL 0x80000000 + +#define VB2_SISLVDSBRIDGE (VB2_301LV | VB2_302LV | VB2_302ELV | VB2_307LV) +#define VB2_SISTMDSBRIDGE (VB2_301 | VB2_301B | VB2_301C | VB2_302B | VB2_307T) +#define VB2_SISBRIDGE (VB2_SISLVDSBRIDGE | VB2_SISTMDSBRIDGE) + +#define VB2_SISTMDSLCDABRIDGE (VB2_301C | VB2_307T) +#define VB2_SISLCDABRIDGE (VB2_SISTMDSLCDABRIDGE | VB2_301LV | VB2_302LV | VB2_302ELV | VB2_307LV) + +#define VB2_SISHIVISIONBRIDGE (VB2_301 | VB2_301B | VB2_302B) +#define VB2_SISYPBPRBRIDGE (VB2_301C | VB2_307T | VB2_SISLVDSBRIDGE) +#define VB2_SISYPBPRARBRIDGE (VB2_301C | VB2_307T | VB2_307LV) +#define VB2_SISTAP4SCALER (VB2_301C | VB2_307T | VB2_302ELV | VB2_307LV) +#define VB2_SISTVBRIDGE (VB2_SISHIVISIONBRIDGE | VB2_SISYPBPRBRIDGE) + +#define VB2_SISVGA2BRIDGE (VB2_301 | VB2_301B | VB2_301C | VB2_302B | VB2_307T) + +#define VB2_VIDEOBRIDGE (VB2_SISBRIDGE | VB2_LVDS | VB2_CHRONTEL | VB2_CONEXANT) + +#define VB2_30xB (VB2_301B | VB2_301C | VB2_302B | VB2_307T) +#define VB2_30xBLV (VB2_30xB | VB2_SISLVDSBRIDGE) +#define VB2_30xC (VB2_301C | VB2_307T) +#define VB2_30xCLV (VB2_301C | VB2_307T | VB2_302ELV| VB2_307LV) +#define VB2_SISEMIBRIDGE (VB2_302LV | VB2_302ELV | VB2_307LV) +#define VB2_LCD162MHZBRIDGE (VB2_301C | VB2_307T) +#define VB2_LCDOVER1280BRIDGE (VB2_301C | VB2_307T | VB2_302LV | VB2_302ELV | VB2_307LV) +#define VB2_LCDOVER1600BRIDGE (VB2_307T | VB2_307LV) +#define VB2_RAMDAC202MHZBRIDGE (VB2_301C | VB2_307T) /* I/O port access macros */ -#define inSISREG(base) inb(base) +#define inSISREG(base) inb(base) -#define outSISREG(base,val) outb(val,base) +#define outSISREG(base,val) outb(val,base) #define orSISREG(base,val) \ - do { \ - u8 __Temp = inSISREG(base); \ - outSISREG(base, __Temp | (val)); \ - } while (0) + do { \ + u8 __Temp = inSISREG(base); \ + outSISREG(base, __Temp | (val));\ + } while (0) #define andSISREG(base,val) \ - do { \ - u8 __Temp = inSISREG(base); \ - outSISREG(base, __Temp & (val)); \ - } while (0) - -#define inSISIDXREG(base,idx,var) \ - do { \ - outSISREG(base, idx); \ - var = inSISREG((base)+1); \ - } while (0) - -#define outSISIDXREG(base,idx,val) \ - do { \ - outSISREG(base, idx); \ - outSISREG((base)+1, val); \ - } while (0) - -#define orSISIDXREG(base,idx,val) \ - do { \ - u8 __Temp; \ - outSISREG(base, idx); \ - __Temp = inSISREG((base)+1) | (val); \ - outSISREG((base)+1, __Temp); \ - } while (0) - -#define andSISIDXREG(base,idx,and) \ - do { \ - u8 __Temp; \ - outSISREG(base, idx); \ - __Temp = inSISREG((base)+1) & (and); \ - outSISREG((base)+1, __Temp); \ - } while (0) - -#define setSISIDXREG(base,idx,and,or) \ - do { \ - u8 __Temp; \ - outSISREG(base, idx); \ - __Temp = (inSISREG((base)+1) & (and)) | (or); \ - outSISREG((base)+1, __Temp); \ - } while (0) + do { \ + u8 __Temp = inSISREG(base); \ + outSISREG(base, __Temp & (val));\ + } while (0) + +#define inSISIDXREG(base,idx,var) \ + do { \ + outSISREG(base, idx); \ + var = inSISREG((base)+1); \ + } while (0) + +#define outSISIDXREG(base,idx,val) \ + do { \ + outSISREG(base, idx); \ + outSISREG((base)+1, val); \ + } while (0) + +#define orSISIDXREG(base,idx,val) \ + do { \ + u8 __Temp; \ + outSISREG(base, idx); \ + __Temp = inSISREG((base)+1) | (val); \ + outSISREG((base)+1, __Temp); \ + } while (0) + +#define andSISIDXREG(base,idx,and) \ + do { \ + u8 __Temp; \ + outSISREG(base, idx); \ + __Temp = inSISREG((base)+1) & (and); \ + outSISREG((base)+1, __Temp); \ + } while (0) + +#define setSISIDXREG(base,idx,and,or) \ + do { \ + u8 __Temp; \ + outSISREG(base, idx); \ + __Temp = (inSISREG((base)+1) & (and)) | (or); \ + outSISREG((base)+1, __Temp); \ + } while (0) /* MMIO access macros */ #define MMIO_IN8(base, offset) readb((base+offset)) @@ -322,19 +419,19 @@ #define MMIO_QUEUE_READPORT Q_READ_PTR #ifndef FB_BLANK_UNBLANK -#define FB_BLANK_UNBLANK 0 +#define FB_BLANK_UNBLANK 0 #endif #ifndef FB_BLANK_NORMAL -#define FB_BLANK_NORMAL 1 +#define FB_BLANK_NORMAL 1 #endif #ifndef FB_BLANK_VSYNC_SUSPEND -#define FB_BLANK_VSYNC_SUSPEND 2 +#define FB_BLANK_VSYNC_SUSPEND 2 #endif #ifndef FB_BLANK_HSYNC_SUSPEND -#define FB_BLANK_HSYNC_SUSPEND 3 +#define FB_BLANK_HSYNC_SUSPEND 3 #endif #ifndef FB_BLANK_POWERDOWN -#define FB_BLANK_POWERDOWN 4 +#define FB_BLANK_POWERDOWN 4 #endif enum _SIS_LCD_TYPE { @@ -347,18 +444,19 @@ enum _SIS_LCD_TYPE { LCD_1600x1200, LCD_1920x1440, LCD_2048x1536, - LCD_320x480, /* FSTN */ + LCD_320x240, /* FSTN */ LCD_1400x1050, LCD_1152x864, LCD_1152x768, LCD_1280x768, LCD_1024x600, - LCD_640x480_2, /* DSTN */ - LCD_640x480_3, /* DSTN */ + LCD_320x240_2, /* DSTN */ + LCD_320x240_3, /* DSTN */ LCD_848x480, LCD_1280x800, LCD_1680x1050, LCD_1280x720, + LCD_1280x854, LCD_CUSTOM, LCD_UNKNOWN }; @@ -368,31 +466,50 @@ enum _SIS_CMDTYPE { AGP_CMD_QUEUE, VM_CMD_QUEUE, }; -typedef unsigned int SIS_CMDTYPE; + +struct SIS_OH { + struct SIS_OH *poh_next; + struct SIS_OH *poh_prev; + u32 offset; + u32 size; +}; + +struct SIS_OHALLOC { + struct SIS_OHALLOC *poha_next; + struct SIS_OH aoh[1]; +}; + +struct SIS_HEAP { + struct SIS_OH oh_free; + struct SIS_OH oh_used; + struct SIS_OH *poh_freelist; + struct SIS_OHALLOC *poha_chain; + u32 max_freesize; + struct sis_video_info *vinfo; +}; /* Our "par" */ struct sis_video_info { int cardnumber; struct fb_info *memyselfandi; - SIS_HW_INFO sishw_ext; - SiS_Private SiS_Pr; + struct SiS_Private SiS_Pr; - sisfb_info sisfbinfo; /* For ioctl SISFB_GET_INFO */ + struct sisfb_info sisfbinfo; /* For ioctl SISFB_GET_INFO */ struct fb_var_screeninfo default_var; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) struct fb_fix_screeninfo sisfb_fix; - u32 pseudo_palette[17]; + u32 pseudo_palette[17]; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - struct display sis_disp; + struct display sis_disp; struct display_switch sisfb_sw; struct { u16 red, green, blue, pad; - } sis_palette[256]; + } sis_palette[256]; union { #ifdef FBCON_HAS_CFB16 u16 cfb16[16]; @@ -400,10 +517,10 @@ struct sis_video_info { #ifdef FBCON_HAS_CFB32 u32 cfb32[16]; #endif - } sis_fbcon_cmap; + } sis_fbcon_cmap; #endif - struct sisfb_monitor { + struct sisfb_monitor { u16 hmin; u16 hmax; u16 vmin; @@ -411,163 +528,166 @@ struct sis_video_info { u32 dclockmax; u8 feature; BOOLEAN datavalid; - } sisfb_thismonitor; + } sisfb_thismonitor; - int chip_id; + unsigned short chip_id; /* PCI ID of chip */ + unsigned short chip_vendor; /* PCI ID of vendor */ char myid[40]; struct pci_dev *nbridge; + struct pci_dev *lpcdev; int mni; /* Mode number index */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - int currcon; + int currcon; #endif unsigned long video_size; - unsigned long video_base; + unsigned long video_base; unsigned long mmio_size; - unsigned long mmio_base; - unsigned long vga_base; + unsigned long mmio_base; + unsigned long vga_base; + + unsigned long video_offset; - SIS_IOTYPE1 *video_vbase; - SIS_IOTYPE1 *mmio_vbase; + unsigned long UMAsize, LFBsize; - unsigned char *bios_abase; + SIS_IOTYPE1 *video_vbase; + SIS_IOTYPE1 *mmio_vbase; - int mtrr; + unsigned char *bios_abase; + + int mtrr; u32 sisfb_mem; - u32 sisfb_parm_mem; - int sisfb_accel; - int sisfb_ypan; - int sisfb_max; - int sisfb_userom; - int sisfb_useoem; + u32 sisfb_parm_mem; + int sisfb_accel; + int sisfb_ypan; + int sisfb_max; + int sisfb_userom; + int sisfb_useoem; int sisfb_mode_idx; int sisfb_parm_rate; int sisfb_crt1off; int sisfb_forcecrt1; int sisfb_crt2type; int sisfb_crt2flags; - int sisfb_dstn; - int sisfb_fstn; + int sisfb_dstn; + int sisfb_fstn; int sisfb_tvplug; int sisfb_tvstd; - int sisfb_filter; int sisfb_nocrt2rate; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) int sisfb_inverse; #endif - u32 heapstart; /* offset */ - SIS_IOTYPE1 *sisfb_heap_start; /* address */ - SIS_IOTYPE1 *sisfb_heap_end; /* address */ - u32 sisfb_heap_size; + u32 heapstart; /* offset */ + SIS_IOTYPE1 *sisfb_heap_start; /* address */ + SIS_IOTYPE1 *sisfb_heap_end; /* address */ + u32 sisfb_heap_size; int havenoheap; -#if 0 - SIS_HEAP sisfb_heap; -#endif + struct SIS_HEAP sisfb_heap; /* This card's vram heap */ - int video_bpp; - int video_cmap_len; - int video_width; - int video_height; - unsigned int refresh_rate; + int video_bpp; + int video_cmap_len; + int video_width; + int video_height; + unsigned int refresh_rate; - unsigned int chip; - u8 revision_id; + unsigned int chip; + u8 revision_id; + int sisvga_enabled; /* PCI device was enabled */ - int video_linelength; /* real pitch */ + int video_linelength; /* real pitch */ int scrnpitchCRT1; /* pitch regarding interlace */ - u16 DstColor; /* For 2d acceleration */ - u32 SiS310_AccelDepth; - u32 CommandReg; - int cmdqueuelength; + u16 DstColor; /* For 2d acceleration */ + u32 SiS310_AccelDepth; + u32 CommandReg; + int cmdqueuelength; /* Current (for accel) */ + u32 cmdQueueSize; /* Total size in KB */ - spinlock_t lockaccel; /* Do not use outside of kernel! */ + spinlock_t lockaccel; /* Do not use outside of kernel! */ - unsigned int pcibus; - unsigned int pcislot; - unsigned int pcifunc; + unsigned int pcibus; + unsigned int pcislot; + unsigned int pcifunc; - int accel; + int accel; + int engineok; - u16 subsysvendor; - u16 subsysdevice; + u16 subsysvendor; + u16 subsysdevice; - u32 vbflags; /* Replacing deprecated stuff from above */ - u32 currentvbflags; + u32 vbflags; /* Replacing deprecated stuff from above */ + u32 currentvbflags; + u32 vbflags2; int lcdxres, lcdyres; int lcddefmodeidx, tvdefmodeidx, defmodeidx; - u32 CRT2LCDType; /* defined in "SIS_LCD_TYPE" */ - - int current_bpp; - int current_width; - int current_height; - int current_htotal; - int current_vtotal; + u32 CRT2LCDType; /* defined in "SIS_LCD_TYPE" */ + u32 curFSTN, curDSTN; + + int current_bpp; + int current_width; + int current_height; + int current_htotal; + int current_vtotal; int current_linelength; - __u32 current_pixclock; - int current_refresh_rate; + __u32 current_pixclock; + int current_refresh_rate; + + unsigned int current_base; - u8 mode_no; - u8 rate_idx; - int modechanged; - unsigned char modeprechange; + u8 mode_no; + u8 rate_idx; + int modechanged; + unsigned char modeprechange; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - u8 sisfb_lastrates[128]; + u8 sisfb_lastrates[128]; #endif - int newrom; - int registered; + int newrom; + int haveXGIROM; + int registered; int warncount; +#ifdef SIS_OLD_CONFIG_COMPAT + int ioctl32registered; +#endif - int sisvga_engine; - int hwcursor_size; - int CRT2_write_enable; - u8 caps; + int sisvga_engine; + int hwcursor_size; + int CRT2_write_enable; + u8 caps; - u8 detectedpdc; - u8 detectedpdca; - u8 detectedlcda; + u8 detectedpdc; + u8 detectedpdca; + u8 detectedlcda; - SIS_IOTYPE1 *hwcursor_vbase; + SIS_IOTYPE1 *hwcursor_vbase; - int chronteltype; - int tvxpos, tvypos; - u8 p2_1f,p2_20,p2_2b,p2_42,p2_43,p2_01,p2_02; + int chronteltype; + int tvxpos, tvypos; + u8 p2_1f,p2_20,p2_2b,p2_42,p2_43,p2_01,p2_02; int tvx, tvy; - u8 sisfblocked; + u8 sisfblocked; + + struct sisfb_info sisfb_infoblock; + + struct sisfb_cmd sisfb_command; + + u32 sisfb_id; + + u8 sisfb_can_post; + u8 sisfb_card_posted; + u8 sisfb_was_boot_device; struct sis_video_info *next; }; -typedef struct _SIS_OH { - struct _SIS_OH *poh_next; - struct _SIS_OH *poh_prev; - u32 offset; - u32 size; -} SIS_OH; - -typedef struct _SIS_OHALLOC { - struct _SIS_OHALLOC *poha_next; - SIS_OH aoh[1]; -} SIS_OHALLOC; - -typedef struct _SIS_HEAP { - SIS_OH oh_free; - SIS_OH oh_used; - SIS_OH *poh_freelist; - SIS_OHALLOC *poha_chain; - u32 max_freesize; - struct sis_video_info *vinfo; -} SIS_HEAP; - #endif diff --git a/drivers/video/sis/sis_accel.c b/drivers/video/sis/sis_accel.c index 30e90a553e809..bab933e6c6a69 100644 --- a/drivers/video/sis/sis_accel.c +++ b/drivers/video/sis/sis_accel.c @@ -1,6 +1,8 @@ /* - * SiS 300/630/730/540/315/550/65x/74x/330/760 frame buffer driver - * for Linux kernels 2.4.x and 2.6.x + * SiS 300/540/630[S]/730[S], + * SiS 315[E|PRO]/550/[M]650/651/[M]661[F|M]X/740/[M]741[GX]/330/[M]760[GX], + * XGI V3XT/V5/V8, Z7 + * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 * * 2D acceleration part * @@ -19,7 +21,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * * Based on the XFree86/X.org driver which is - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * Author: Thomas Winischhofer <thomas@winischhofer.net> * (see http://www.winischhofer.net/ @@ -30,13 +32,11 @@ #include <linux/version.h> #include <linux/module.h> #include <linux/kernel.h> -#include <linux/errno.h> #include <linux/fb.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #include <linux/console.h> -#include <linux/selection.h> +#endif #include <linux/ioport.h> -#include <linux/capability.h> -#include <linux/fs.h> #include <linux/types.h> #include <asm/io.h> @@ -188,7 +188,7 @@ SiS300SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w } #endif -/* 315/330 series ------------------------------------------------- */ +/* 315/330/340 series ---------------------------------------------- */ #ifdef CONFIG_FB_SIS_315 static void @@ -202,7 +202,7 @@ SiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int tra { SiS310SetupDSTColorDepth(ivideo->DstColor); SiS310SetupSRCPitch(ivideo->video_linelength) - SiS310SetupDSTRect(ivideo->video_linelength, 0xffff) + SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff) if(trans_color != -1) { SiS310SetupROP(0x0A) SiS310SetupSRCTrans(trans_color) @@ -213,7 +213,7 @@ SiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int tra /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */ } SiS310SetupCMDFlag(ivideo->SiS310_AccelDepth) - /* The 315 series is smart enough to know the direction */ + /* The chip is smart enough to know the direction */ } static void @@ -223,35 +223,38 @@ SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int u32 srcbase = 0, dstbase = 0; int mymin = min(src_y, dst_y); int mymax = max(src_y, dst_y); - + /* Although the chip knows the direction to use - * if the source and destination areas overlap, + * if the source and destination areas overlap, * that logic fails if we fiddle with the bitmap * addresses. Therefore, we check if the source - * and destination blitting areas overlap and - * adapt the bitmap addresses synchronously + * and destination blitting areas overlap and + * adapt the bitmap addresses synchronously * if the coordinates exceed the valid range. - * The the areas do not overlap, we do our + * The the areas do not overlap, we do our * normal check. */ - if((mymax - mymin) < height) { - if((src_y >= 2048) || (dst_y >= 2048)) { - srcbase = ivideo->video_linelength * mymin; - dstbase = ivideo->video_linelength * mymin; - src_y -= mymin; - dst_y -= mymin; - } + if((mymax - mymin) < height) { + if((src_y >= 2048) || (dst_y >= 2048)) { + srcbase = ivideo->video_linelength * mymin; + dstbase = ivideo->video_linelength * mymin; + src_y -= mymin; + dst_y -= mymin; + } } else { - if(src_y >= 2048) { - srcbase = ivideo->video_linelength * src_y; - src_y = 0; - } - if(dst_y >= 2048) { - dstbase = ivideo->video_linelength * dst_y; - dst_y = 0; - } + if(src_y >= 2048) { + srcbase = ivideo->video_linelength * src_y; + src_y = 0; + } + if(dst_y >= 2048) { + dstbase = ivideo->video_linelength * dst_y; + dst_y = 0; + } } + srcbase += ivideo->video_offset; + dstbase += ivideo->video_offset; + SiS310SetupSRCBase(srcbase); SiS310SetupDSTBase(dstbase); SiS310SetupRect(width, height) @@ -264,7 +267,7 @@ static void SiS310SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop) { SiS310SetupPATFG(color) - SiS310SetupDSTRect(ivideo->video_linelength, 0xffff) + SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff) SiS310SetupDSTColorDepth(ivideo->DstColor); SiS310SetupROP(sisPatALUConv[rop]) SiS310SetupCMDFlag(PATFG | ivideo->SiS310_AccelDepth) @@ -279,6 +282,7 @@ SiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w dstbase = ivideo->video_linelength * y; y = 0; } + dstbase += ivideo->video_offset; SiS310SetupDSTBase(dstbase) SiS310SetupDSTXY(x,y) SiS310SetupRect(w,h) @@ -294,384 +298,153 @@ SiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w int sisfb_initaccel(struct sis_video_info *ivideo) { #ifdef SISFB_USE_SPINLOCKS - spin_lock_init(&ivideo->lockaccel); + spin_lock_init(&ivideo->lockaccel); #endif - return(0); + return 0; } void sisfb_syncaccel(struct sis_video_info *ivideo) { - if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 - SiS300Sync(ivideo); + SiS300Sync(ivideo); #endif - } else { + } else { #ifdef CONFIG_FB_SIS_315 - SiS310Sync(ivideo); + SiS310Sync(ivideo); #endif - } + } } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* --------------- 2.5 --------------- */ int fbcon_sis_sync(struct fb_info *info) { - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - CRITFLAGS + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + CRITFLAGS - if(!ivideo->accel) - return 0; + if((!ivideo->accel) || (!ivideo->engineok)) + return 0; - if(ivideo->sisvga_engine == SIS_300_VGA) { -#ifdef CONFIG_FB_SIS_300 - SiS300Sync(ivideo); -#endif - } else { -#ifdef CONFIG_FB_SIS_315 - SiS310Sync(ivideo); -#endif - } - CRITEND - return 0; + CRITBEGIN + sisfb_syncaccel(ivideo); + CRITEND + + return 0; } void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - u32 col = 0; - u32 vxres = info->var.xres_virtual; - u32 vyres = info->var.yres_virtual; - int width, height; - CRITFLAGS - - if(info->state != FBINFO_STATE_RUNNING) { - return; - } - - if(!ivideo->accel) { - cfb_fillrect(info, rect); - return; - } - - if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres) { - return; - } - - /* Clipping */ - width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width; - height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height; - - switch(info->var.bits_per_pixel) { + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + u32 col = 0; + u32 vxres = info->var.xres_virtual; + u32 vyres = info->var.yres_virtual; + int width, height; + CRITFLAGS + + if(info->state != FBINFO_STATE_RUNNING) + return; + + if((!ivideo->accel) || (!ivideo->engineok)) { + cfb_fillrect(info, rect); + return; + } + + if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres) + return; + + /* Clipping */ + width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width; + height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height; + + switch(info->var.bits_per_pixel) { case 8: col = rect->color; break; case 16: case 32: col = ((u32 *)(info->pseudo_palette))[rect->color]; break; - } + } - if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 - CRITBEGIN - SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]); - SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height); - CRITEND - SiS300Sync(ivideo); + CRITBEGIN + SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]); + SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height); + CRITEND #endif - } else { + } else { #ifdef CONFIG_FB_SIS_315 - CRITBEGIN - SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]); - SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height); - CRITEND - SiS310Sync(ivideo); + CRITBEGIN + SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]); + SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height); + CRITEND #endif - } + } + sisfb_syncaccel(ivideo); } void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area) { - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - u32 vxres = info->var.xres_virtual; - u32 vyres = info->var.yres_virtual; - int width = area->width; - int height = area->height; - CRITFLAGS - - if(info->state != FBINFO_STATE_RUNNING) { - return; - } - - if(!ivideo->accel) { - cfb_copyarea(info, area); - return; - } - - if(!width || !height || - area->sx >= vxres || area->sy >= vyres || - area->dx >= vxres || area->dy >= vyres) { - return; - } - - /* Clipping */ - if((area->sx + width) > vxres) width = vxres - area->sx; - if((area->dx + width) > vxres) width = vxres - area->dx; - if((area->sy + height) > vyres) height = vyres - area->sy; - if((area->dy + height) > vyres) height = vyres - area->dy; - - if(ivideo->sisvga_engine == SIS_300_VGA) { -#ifdef CONFIG_FB_SIS_300 - int xdir, ydir; - - if(area->sx < area->dx) xdir = 0; - else xdir = 1; - if(area->sy < area->dy) ydir = 0; - else ydir = 1; - - CRITBEGIN - SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1); - SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, area->dx, area->dy, - width, height); - CRITEND - SiS300Sync(ivideo); -#endif - } else { -#ifdef CONFIG_FB_SIS_315 - CRITBEGIN - SiS310SetupForScreenToScreenCopy(ivideo, 3, -1); - SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, area->dx, area->dy, - width, height); - CRITEND - SiS310Sync(ivideo); -#endif - } -} - -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* -------------- 2.4 --------------- */ - -void fbcon_sis_bmove(struct display *p, int srcy, int srcx, - int dsty, int dstx, int height, int width) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; - + struct sis_video_info *ivideo = (struct sis_video_info *)info->par; + u32 vxres = info->var.xres_virtual; + u32 vyres = info->var.yres_virtual; + int width = area->width; + int height = area->height; CRITFLAGS - if(!ivideo->accel) { - switch(ivideo->video_bpp) { - case 8: -#ifdef FBCON_HAS_CFB8 - fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width); -#endif - break; - case 16: -#ifdef FBCON_HAS_CFB16 - fbcon_cfb16_bmove(p, srcy, srcx, dsty, dstx, height, width); -#endif - break; - case 32: -#ifdef FBCON_HAS_CFB32 - fbcon_cfb32_bmove(p, srcy, srcx, dsty, dstx, height, width); -#endif - break; - } - return; - } - - srcx *= fontwidth(p); - srcy *= fontheight(p); - dstx *= fontwidth(p); - dsty *= fontheight(p); - width *= fontwidth(p); - height *= fontheight(p); + if(info->state != FBINFO_STATE_RUNNING) + return; - if(ivideo->sisvga_engine == SIS_300_VGA) { -#ifdef CONFIG_FB_SIS_300 - int xdir, ydir; - - if(srcx < dstx) xdir = 0; - else xdir = 1; - if(srcy < dsty) ydir = 0; - else ydir = 1; - - CRITBEGIN - SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1); - SiS300SubsequentScreenToScreenCopy(ivideo, srcx, srcy, dstx, dsty, width, height); - CRITEND - SiS300Sync(ivideo); -#endif - } else { -#ifdef CONFIG_FB_SIS_315 - CRITBEGIN - SiS310SetupForScreenToScreenCopy(ivideo, 3, -1); - SiS310SubsequentScreenToScreenCopy(ivideo, srcx, srcy, dstx, dsty, width, height); - CRITEND - SiS310Sync(ivideo); -#endif + if((!ivideo->accel) || (!ivideo->engineok)) { + cfb_copyarea(info, area); + return; } -} -static void fbcon_sis_clear(struct vc_data *conp, struct display *p, - int srcy, int srcx, int height, int width, int color) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; - CRITFLAGS + if(!width || !height || + area->sx >= vxres || area->sy >= vyres || + area->dx >= vxres || area->dy >= vyres) + return; - srcx *= fontwidth(p); - srcy *= fontheight(p); - width *= fontwidth(p); - height *= fontheight(p); + /* Clipping */ + if((area->sx + width) > vxres) width = vxres - area->sx; + if((area->dx + width) > vxres) width = vxres - area->dx; + if((area->sy + height) > vyres) height = vyres - area->sy; + if((area->dy + height) > vyres) height = vyres - area->dy; if(ivideo->sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 - CRITBEGIN - SiS300SetupForSolidFill(ivideo, color, 3); - SiS300SubsequentSolidFillRect(ivideo, srcx, srcy, width, height); - CRITEND - SiS300Sync(ivideo); + int xdir, ydir; + + if(area->sx < area->dx) xdir = 0; + else xdir = 1; + if(area->sy < area->dy) ydir = 0; + else ydir = 1; + + CRITBEGIN + SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1); + SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, + area->dx, area->dy, width, height); + CRITEND #endif } else { #ifdef CONFIG_FB_SIS_315 - CRITBEGIN - SiS310SetupForSolidFill(ivideo, color, 3); - SiS310SubsequentSolidFillRect(ivideo, srcx, srcy, width, height); - CRITEND - SiS310Sync(ivideo); -#endif - } -} - -void fbcon_sis_clear8(struct vc_data *conp, struct display *p, - int srcy, int srcx, int height, int width) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; - u32 bgx; - - if(!ivideo->accel) { -#ifdef FBCON_HAS_CFB8 - fbcon_cfb8_clear(conp, p, srcy, srcx, height, width); + CRITBEGIN + SiS310SetupForScreenToScreenCopy(ivideo, 3, -1); + SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, + area->dx, area->dy, width, height); + CRITEND #endif - return; } - bgx = attr_bgcol_ec(p, conp); - fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx); + sisfb_syncaccel(ivideo); } -void fbcon_sis_clear16(struct vc_data *conp, struct display *p, - int srcy, int srcx, int height, int width) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; - u32 bgx; - - if(!ivideo->accel) { -#ifdef FBCON_HAS_CFB16 - fbcon_cfb16_clear(conp, p, srcy, srcx, height, width); #endif - return; - } - - bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx); -} -void fbcon_sis_clear32(struct vc_data *conp, struct display *p, - int srcy, int srcx, int height, int width) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; - u32 bgx; - - if(!ivideo->accel) { -#ifdef FBCON_HAS_CFB32 - fbcon_cfb32_clear(conp, p, srcy, srcx, height, width); -#endif - return; - } - - bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx); -} - -void fbcon_sis_revc(struct display *p, int srcx, int srcy) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par; - CRITFLAGS - - if(!ivideo->accel) { - switch(ivideo->video_bpp) { - case 16: -#ifdef FBCON_HAS_CFB16 - fbcon_cfb16_revc(p, srcx, srcy); -#endif - break; - case 32: -#ifdef FBCON_HAS_CFB32 - fbcon_cfb32_revc(p, srcx, srcy); -#endif - break; - } - return; - } - - srcx *= fontwidth(p); - srcy *= fontheight(p); - - if(ivideo->sisvga_engine == SIS_300_VGA) { -#ifdef CONFIG_FB_SIS_300 - CRITBEGIN - SiS300SetupForSolidFill(ivideo, 0, 0x0a); - SiS300SubsequentSolidFillRect(ivideo, srcx, srcy, fontwidth(p), fontheight(p)); - CRITEND - SiS300Sync(ivideo); -#endif - } else { -#ifdef CONFIG_FB_SIS_315 - CRITBEGIN - SiS310SetupForSolidFill(ivideo, 0, 0x0a); - SiS310SubsequentSolidFillRect(ivideo, srcx, srcy, fontwidth(p), fontheight(p)); - CRITEND - SiS310Sync(ivideo); -#endif - } -} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* -------------- 2.4 --------------- */ -#ifdef FBCON_HAS_CFB8 -struct display_switch fbcon_sis8 = { - .setup = fbcon_cfb8_setup, - .bmove = fbcon_sis_bmove, - .clear = fbcon_sis_clear8, - .putc = fbcon_cfb8_putc, - .putcs = fbcon_cfb8_putcs, - .revc = fbcon_cfb8_revc, - .clear_margins = fbcon_cfb8_clear_margins, - .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) -}; -#endif -#ifdef FBCON_HAS_CFB16 -struct display_switch fbcon_sis16 = { - .setup = fbcon_cfb16_setup, - .bmove = fbcon_sis_bmove, - .clear = fbcon_sis_clear16, - .putc = fbcon_cfb16_putc, - .putcs = fbcon_cfb16_putcs, - .revc = fbcon_sis_revc, - .clear_margins = fbcon_cfb16_clear_margins, - .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) -}; -#endif -#ifdef FBCON_HAS_CFB32 -struct display_switch fbcon_sis32 = { - .setup = fbcon_cfb32_setup, - .bmove = fbcon_sis_bmove, - .clear = fbcon_sis_clear32, - .putc = fbcon_cfb32_putc, - .putcs = fbcon_cfb32_putcs, - .revc = fbcon_sis_revc, - .clear_margins = fbcon_cfb32_clear_margins, - .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) -}; -#endif +#include "sisfb_accel_2_4.h" #endif /* KERNEL VERSION */ diff --git a/drivers/video/sis/sis_accel.h b/drivers/video/sis/sis_accel.h index bb28f331d60d3..046e2c4a8e09c 100644 --- a/drivers/video/sis/sis_accel.h +++ b/drivers/video/sis/sis_accel.h @@ -1,6 +1,8 @@ /* - * SiS 300/630/730/540/315/550/650/740 frame buffer driver - * for Linux kernels 2.4.x and 2.5.x + * SiS 300/540/630[S]/730[S], + * SiS 315[E|PRO]/550/[M]650/651/[M]661[F|M]X/740/[M]741[GX]/330/[M]760[GX], + * XGI V3XT/V5/V8, Z7 + * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 * * 2D acceleration part * @@ -283,6 +285,8 @@ { \ while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ + while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ + while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \ CmdQueLen = 0; \ } @@ -402,6 +406,7 @@ void fbcon_sis_clear32(struct vc_data *conp, struct display *p, int srcy, int srcx, int height, int width); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) +int fbcon_sis_sync(struct fb_info *info); void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect); void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area); #endif diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 6982660368193..42c54b69726e8 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -1,9 +1,10 @@ /* - * SiS 300/305/540/630(S)/730(S) - * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760 + * SiS 300/540/630[S]/730[S], + * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX], + * XGI V3XT/V5/V8, Z7 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3 * - * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria. + * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria. * * 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 @@ -19,11 +20,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * - * Author: Thomas Winischhofer <thomas@winischhofer.net> + * Author: Thomas Winischhofer <thomas@winischhofer.net> * * Author of (practically wiped) code base: * SiS (www.sis.com) - * Copyright (C) 1999 Silicon Integrated Systems, Inc. + * Copyright (C) 1999 Silicon Integrated Systems, Inc. * * See http://www.winischhofer.net/ for more information and updates * @@ -46,16 +47,15 @@ #include <linux/mm.h> #include <linux/tty.h> #include <linux/slab.h> -#include <linux/delay.h> #include <linux/fb.h> -#include <linux/console.h> #include <linux/selection.h> -#include <linux/smp_lock.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/vmalloc.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #include <linux/vt_kern.h> +#endif #include <linux/capability.h> #include <linux/fs.h> #include <linux/types.h> @@ -94,71 +94,75 @@ extern struct display_switch fbcon_sis32; #endif #endif +static void sisfb_handle_command(struct sis_video_info *ivideo, + struct sisfb_cmd *sisfb_command); + /* ------------------ Internal helper routines ----------------- */ static void __init sisfb_setdefaultparms(void) { - sisfb_off = 0; - sisfb_parm_mem = 0; - sisfb_accel = -1; - sisfb_ypan = -1; - sisfb_max = -1; - sisfb_userom = -1; - sisfb_useoem = -1; + sisfb_off = 0; + sisfb_parm_mem = 0; + sisfb_accel = -1; + sisfb_ypan = -1; + sisfb_max = -1; + sisfb_userom = -1; + sisfb_useoem = -1; #ifdef MODULE /* Module: "None" for 2.4, default mode for 2.5+ */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - sisfb_mode_idx = -1; + sisfb_mode_idx = -1; #else - sisfb_mode_idx = MODE_INDEX_NONE; + sisfb_mode_idx = MODE_INDEX_NONE; #endif #else /* Static: Default mode */ - sisfb_mode_idx = -1; -#endif - sisfb_parm_rate = -1; - sisfb_crt1off = 0; - sisfb_forcecrt1 = -1; - sisfb_crt2type = -1; - sisfb_crt2flags = 0; - sisfb_pdc = 0xff; - sisfb_pdca = 0xff; - sisfb_scalelcd = -1; + sisfb_mode_idx = -1; +#endif + sisfb_parm_rate = -1; + sisfb_crt1off = 0; + sisfb_forcecrt1 = -1; + sisfb_crt2type = -1; + sisfb_crt2flags = 0; + sisfb_pdc = 0xff; + sisfb_pdca = 0xff; + sisfb_scalelcd = -1; sisfb_specialtiming = CUT_NONE; - sisfb_lvdshl = -1; - sisfb_dstn = 0; - sisfb_fstn = 0; - sisfb_tvplug = -1; - sisfb_tvstd = -1; - sisfb_tvxposoffset = 0; - sisfb_tvyposoffset = 0; - sisfb_filter = -1; - sisfb_nocrt2rate = 0; + sisfb_lvdshl = -1; + sisfb_dstn = 0; + sisfb_fstn = 0; + sisfb_tvplug = -1; + sisfb_tvstd = -1; + sisfb_tvxposoffset = 0; + sisfb_tvyposoffset = 0; + sisfb_nocrt2rate = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - sisfb_inverse = 0; - sisfb_fontname[0] = 0; + sisfb_inverse = 0; + sisfb_fontname[0] = 0; #endif #if !defined(__i386__) && !defined(__x86_64__) - sisfb_resetcard = 0; - sisfb_videoram = 0; + sisfb_resetcard = 0; + sisfb_videoram = 0; #endif } +/* ------------- Parameter parsing -------------- */ + static void __devinit sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet) { int i = 0, j = 0; - /* BEWARE: We don't know the hardware specs yet and there is no ivideo */ + /* We don't know the hardware specs yet and there is no ivideo */ if(vesamode == 0) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) sisfb_mode_idx = MODE_INDEX_NONE; #else - if(!quiet) { - printk(KERN_ERR "sisfb: Invalid mode. Using default.\n"); - } + if(!quiet) + printk(KERN_ERR "sisfb: Invalid mode. Using default.\n"); + sisfb_mode_idx = DEFAULT_MODE; #endif return; @@ -169,95 +173,102 @@ sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet) while(sisbios_mode[i++].mode_no[0] != 0) { if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) || (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) { - if(sisfb_fstn) { - if(sisbios_mode[i-1].mode_no[1] == 0x50 || - sisbios_mode[i-1].mode_no[1] == 0x56 || - sisbios_mode[i-1].mode_no[1] == 0x53) continue; - } else { - if(sisbios_mode[i-1].mode_no[1] == 0x5a || - sisbios_mode[i-1].mode_no[1] == 0x5b) continue; - } - sisfb_mode_idx = i - 1; - j = 1; - break; + if(sisfb_fstn) { + if(sisbios_mode[i-1].mode_no[1] == 0x50 || + sisbios_mode[i-1].mode_no[1] == 0x56 || + sisbios_mode[i-1].mode_no[1] == 0x53) + continue; + } else { + if(sisbios_mode[i-1].mode_no[1] == 0x5a || + sisbios_mode[i-1].mode_no[1] == 0x5b) + continue; + } + sisfb_mode_idx = i - 1; + j = 1; + break; } } - if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode); + if((!j) && !quiet) + printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode); } -static void +static void __devinit sisfb_search_mode(char *name, BOOLEAN quiet) { - int i = 0; unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0; + int i = 0; char strbuf[16], strbuf1[20]; char *nameptr = name; - /* BEWARE: We don't know the hardware specs yet and there is no ivideo */ + /* We don't know the hardware specs yet and there is no ivideo */ if(name == NULL) { - if(!quiet) { - printk(KERN_ERR "sisfb: Internal error, using default mode.\n"); - } - sisfb_mode_idx = DEFAULT_MODE; - return; + if(!quiet) + printk(KERN_ERR "sisfb: Internal error, using default mode.\n"); + + sisfb_mode_idx = DEFAULT_MODE; + return; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) { - if(!quiet) { - printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n"); - } - sisfb_mode_idx = DEFAULT_MODE; - return; + if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) { + if(!quiet) + printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n"); + + sisfb_mode_idx = DEFAULT_MODE; + return; } #endif if(strlen(name) <= 19) { - strcpy(strbuf1, name); - for(i=0; i<strlen(strbuf1); i++) { - if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' '; - } + strcpy(strbuf1, name); + for(i = 0; i < strlen(strbuf1); i++) { + if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' '; + } - /* This does some fuzzy mode naming detection */ - if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) { - if((rate <= 32) || (depth > 32)) { - j = rate; rate = depth; depth = j; - } - sprintf(strbuf, "%ux%ux%u", xres, yres, depth); - nameptr = strbuf; - sisfb_parm_rate = rate; - } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) { - sprintf(strbuf, "%ux%ux%u", xres, yres, depth); - nameptr = strbuf; - } else { - xres = 0; - if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) { - sprintf(strbuf, "%ux%ux8", xres, yres); - nameptr = strbuf; - } else { - sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet); - return; - } - } + /* This does some fuzzy mode naming detection */ + if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) { + if((rate <= 32) || (depth > 32)) { + j = rate; rate = depth; depth = j; + } + sprintf(strbuf, "%ux%ux%u", xres, yres, depth); + nameptr = strbuf; + sisfb_parm_rate = rate; + } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) { + sprintf(strbuf, "%ux%ux%u", xres, yres, depth); + nameptr = strbuf; + } else { + xres = 0; + if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) { + sprintf(strbuf, "%ux%ux8", xres, yres); + nameptr = strbuf; + } else { + sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet); + return; + } + } } i = 0; j = 0; while(sisbios_mode[i].mode_no[0] != 0) { if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) { - if(sisfb_fstn) { - if(sisbios_mode[i-1].mode_no[1] == 0x50 || - sisbios_mode[i-1].mode_no[1] == 0x56 || - sisbios_mode[i-1].mode_no[1] == 0x53) continue; - } else { - if(sisbios_mode[i-1].mode_no[1] == 0x5a || - sisbios_mode[i-1].mode_no[1] == 0x5b) continue; - } - sisfb_mode_idx = i - 1; - j = 1; - break; - } - } - if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr); + if(sisfb_fstn) { + if(sisbios_mode[i-1].mode_no[1] == 0x50 || + sisbios_mode[i-1].mode_no[1] == 0x56 || + sisbios_mode[i-1].mode_no[1] == 0x53) + continue; + } else { + if(sisbios_mode[i-1].mode_no[1] == 0x5a || + sisbios_mode[i-1].mode_no[1] == 0x5b) + continue; + } + sisfb_mode_idx = i - 1; + j = 1; + break; + } + } + + if((!j) && !quiet) + printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr); } #ifndef MODULE @@ -265,7 +276,7 @@ static void __devinit sisfb_get_vga_mode_from_kernel(void) { #if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT) - char mymode[32]; + char mymode[32]; int mydepth = screen_info.lfb_depth; if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return; @@ -274,15 +285,17 @@ sisfb_get_vga_mode_from_kernel(void) (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) && (mydepth >= 8) && (mydepth <= 32) ) { - if(mydepth == 24) mydepth = 32; + if(mydepth == 24) mydepth = 32; - sprintf(mymode, "%ux%ux%u", screen_info.lfb_width, - screen_info.lfb_height, + sprintf(mymode, "%ux%ux%u", screen_info.lfb_width, + screen_info.lfb_height, mydepth); - printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode); + printk(KERN_DEBUG + "sisfb: Using vga mode %s pre-set by kernel as default\n", + mymode); - sisfb_search_mode(mymode, TRUE); + sisfb_search_mode(mymode, TRUE); } #endif return; @@ -294,26 +307,25 @@ sisfb_search_crt2type(const char *name) { int i = 0; - /* BEWARE: We don't know the hardware specs yet and there is no ivideo */ + /* We don't know the hardware specs yet and there is no ivideo */ if(name == NULL) return; while(sis_crt2type[i].type_no != -1) { - if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) { - sisfb_crt2type = sis_crt2type[i].type_no; - sisfb_tvplug = sis_crt2type[i].tvplug_no; - sisfb_crt2flags = sis_crt2type[i].flags; - break; - } - i++; + if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) { + sisfb_crt2type = sis_crt2type[i].type_no; + sisfb_tvplug = sis_crt2type[i].tvplug_no; + sisfb_crt2flags = sis_crt2type[i].flags; + break; + } + i++; } sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0; sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0; - if(sisfb_crt2type < 0) { + if(sisfb_crt2type < 0) printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name); - } } static void __init @@ -321,16 +333,17 @@ sisfb_search_tvstd(const char *name) { int i = 0; - /* BEWARE: We don't know the hardware specs yet and there is no ivideo */ + /* We don't know the hardware specs yet and there is no ivideo */ - if(name == NULL) return; + if(name == NULL) + return; while(sis_tvtype[i].type_no != -1) { - if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) { - sisfb_tvstd = sis_tvtype[i].type_no; - break; - } - i++; + if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) { + sisfb_tvstd = sis_tvtype[i].type_no; + break; + } + i++; } } @@ -340,38 +353,101 @@ sisfb_search_specialtiming(const char *name) int i = 0; BOOLEAN found = FALSE; - /* BEWARE: We don't know the hardware specs yet and there is no ivideo */ + /* We don't know the hardware specs yet and there is no ivideo */ - if(name == NULL) return; + if(name == NULL) + return; if(!strnicmp(name, "none", 4)) { - sisfb_specialtiming = CUT_FORCENONE; + sisfb_specialtiming = CUT_FORCENONE; printk(KERN_DEBUG "sisfb: Special timing disabled\n"); } else { - while(mycustomttable[i].chipID != 0) { - if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) { - sisfb_specialtiming = mycustomttable[i].SpecialID; - found = TRUE; - printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n", - mycustomttable[i].vendorName, mycustomttable[i].cardName, - mycustomttable[i].optionName); - break; - } - i++; - } - if(!found) { - printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:"); - printk(KERN_WARNING "\t\"none\" (to disable special timings)\n"); - i = 0; - while(mycustomttable[i].chipID != 0) { - printk(KERN_WARNING "\t\"%s\" (for %s %s)\n", - mycustomttable[i].optionName, - mycustomttable[i].vendorName, - mycustomttable[i].cardName); - i++; - } - } - } + while(mycustomttable[i].chipID != 0) { + if(!strnicmp(name,mycustomttable[i].optionName, + strlen(mycustomttable[i].optionName))) { + sisfb_specialtiming = mycustomttable[i].SpecialID; + found = TRUE; + printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n", + mycustomttable[i].vendorName, + mycustomttable[i].cardName, + mycustomttable[i].optionName); + break; + } + i++; + } + if(!found) { + printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:"); + printk(KERN_WARNING "\t\"none\" (to disable special timings)\n"); + i = 0; + while(mycustomttable[i].chipID != 0) { + printk(KERN_WARNING "\t\"%s\" (for %s %s)\n", + mycustomttable[i].optionName, + mycustomttable[i].vendorName, + mycustomttable[i].cardName); + i++; + } + } + } +} + +/* ----------- Various detection routines ----------- */ + +static void __devinit +sisfb_detect_custom_timing(struct sis_video_info *ivideo) +{ + unsigned char *biosver = NULL; + unsigned char *biosdate = NULL; + BOOLEAN footprint; + u32 chksum = 0; + int i, j; + + if(ivideo->SiS_Pr.UseROM) { + biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06; + biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c; + for(i = 0; i < 32768; i++) + chksum += ivideo->SiS_Pr.VirtualRomBase[i]; + } + + i = 0; + do { + if( (mycustomttable[i].chipID == ivideo->chip) && + ((!strlen(mycustomttable[i].biosversion)) || + (ivideo->SiS_Pr.UseROM && + (!strncmp(mycustomttable[i].biosversion, biosver, + strlen(mycustomttable[i].biosversion))))) && + ((!strlen(mycustomttable[i].biosdate)) || + (ivideo->SiS_Pr.UseROM && + (!strncmp(mycustomttable[i].biosdate, biosdate, + strlen(mycustomttable[i].biosdate))))) && + ((!mycustomttable[i].bioschksum) || + (ivideo->SiS_Pr.UseROM && + (mycustomttable[i].bioschksum == chksum))) && + (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) && + (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) { + footprint = TRUE; + for(j = 0; j < 5; j++) { + if(mycustomttable[i].biosFootprintAddr[j]) { + if(ivideo->SiS_Pr.UseROM) { + if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] != + mycustomttable[i].biosFootprintData[j]) { + footprint = FALSE; + } + } else + footprint = FALSE; + } + } + if(footprint) { + ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID; + printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n", + mycustomttable[i].vendorName, + mycustomttable[i].cardName); + printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n", + mycustomttable[i].optionName); + break; + } + } + i++; + } while(mycustomttable[i].chipID); } static BOOLEAN __devinit @@ -384,22 +460,23 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer) buffer[2] != 0xff || buffer[3] != 0xff || buffer[4] != 0xff || buffer[5] != 0xff || buffer[6] != 0xff || buffer[7] != 0x00) { - printk(KERN_DEBUG "sisfb: Bad EDID header\n"); - return FALSE; + printk(KERN_DEBUG "sisfb: Bad EDID header\n"); + return FALSE; } if(buffer[0x12] != 0x01) { - printk(KERN_INFO "sisfb: EDID version %d not supported\n", - buffer[0x12]); - return FALSE; + printk(KERN_INFO "sisfb: EDID version %d not supported\n", + buffer[0x12]); + return FALSE; } monitor->feature = buffer[0x18]; if(!buffer[0x14] & 0x80) { - if(!(buffer[0x14] & 0x08)) { - printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n"); - } + if(!(buffer[0x14] & 0x08)) { + printk(KERN_INFO + "sisfb: WARNING: Monitor does not support separate syncs\n"); + } } if(buffer[0x13] >= 0x01) { @@ -409,7 +486,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer) j = 0x36; for(i=0; i<4; i++) { if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 && - buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd && + buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd && buffer[j + 4] == 0x00) { monitor->hmin = buffer[j + 7]; monitor->hmax = buffer[j + 8]; @@ -435,7 +512,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer) emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16); for(i = 0; i < 13; i++) { if(emodes & sisfb_ddcsmodes[i].mask) { - if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h; + if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h; if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1; if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v; if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v; @@ -446,80 +523,81 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer) for(i = 0; i < 8; i++) { xres = (buffer[index] + 31) * 8; switch(buffer[index + 1] & 0xc0) { - case 0xc0: yres = (xres * 9) / 16; break; - case 0x80: yres = (xres * 4) / 5; break; - case 0x40: yres = (xres * 3) / 4; break; - default: yres = xres; break; + case 0xc0: yres = (xres * 9) / 16; break; + case 0x80: yres = (xres * 4) / 5; break; + case 0x40: yres = (xres * 3) / 4; break; + default: yres = xres; break; } refresh = (buffer[index + 1] & 0x3f) + 60; if((xres >= 640) && (yres >= 480)) { - for(j = 0; j < 8; j++) { - if((xres == sisfb_ddcfmodes[j].x) && - (yres == sisfb_ddcfmodes[j].y) && + for(j = 0; j < 8; j++) { + if((xres == sisfb_ddcfmodes[j].x) && + (yres == sisfb_ddcfmodes[j].y) && (refresh == sisfb_ddcfmodes[j].v)) { if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h; if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1; if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v; if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v; - if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[i].d; - } - } + if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d; + } + } } index += 2; - } + } if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) { monitor->datavalid = TRUE; } } - return(monitor->datavalid); + return monitor->datavalid; } static void __devinit sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno) { - USHORT temp, i, realcrtno = crtno; - u8 buffer[256]; + unsigned short temp, i, realcrtno = crtno; + unsigned char buffer[256]; monitor->datavalid = FALSE; if(crtno) { - if(ivideo->vbflags & CRT2_LCD) realcrtno = 1; - else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2; - else return; - } + if(ivideo->vbflags & CRT2_LCD) realcrtno = 1; + else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2; + else return; + } - if((ivideo->sisfb_crt1off) && (!crtno)) return; + if((ivideo->sisfb_crt1off) && (!crtno)) + return; - temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, - realcrtno, 0, &buffer[0]); - if((!temp) || (temp == 0xffff)) { - printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1); + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, + realcrtno, 0, &buffer[0], ivideo->vbflags2); + if((!temp) || (temp == 0xffff)) { + printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1); return; - } else { - printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1); - printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n", - crtno + 1, - (temp & 0x1a) ? "" : "[none of the supported]", - (temp & 0x02) ? "2 " : "", - (temp & 0x08) ? "D&P" : "", - (temp & 0x10) ? "FPDI-2" : ""); - if(temp & 0x02) { + } else { + printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1); + printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n", + crtno + 1, + (temp & 0x1a) ? "" : "[none of the supported]", + (temp & 0x02) ? "2 " : "", + (temp & 0x08) ? "D&P" : "", + (temp & 0x10) ? "FPDI-2" : ""); + if(temp & 0x02) { i = 3; /* Number of retrys */ do { - temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, - realcrtno, 1, &buffer[0]); + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, + realcrtno, 1, &buffer[0], ivideo->vbflags2); } while((temp) && i--); - if(!temp) { - if(sisfb_interpret_edid(monitor, &buffer[0])) { + if(!temp) { + if(sisfb_interpret_edid(monitor, &buffer[0])) { printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n", - monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax, + monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax, monitor->dclockmax / 1000); } else { - printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1); - } + printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1); + } } else { - printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1); + printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1); } } else { printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n"); @@ -527,6 +605,8 @@ sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, i } } +/* -------------- Mode validation --------------- */ + static BOOLEAN sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int mode_idx, int rate_idx, int rate) @@ -534,42 +614,49 @@ sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int htotal, vtotal; unsigned int dclock, hsync; - if(!monitor->datavalid) return TRUE; + if(!monitor->datavalid) + return TRUE; - if(mode_idx < 0) return FALSE; + if(mode_idx < 0) + return FALSE; /* Skip for 320x200, 320x240, 640x400 */ - switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) { - case 0x59: - case 0x41: - case 0x4f: - case 0x50: - case 0x56: - case 0x53: - case 0x2f: - case 0x5d: - case 0x5e: - return TRUE; + switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) { + case 0x59: + case 0x41: + case 0x4f: + case 0x50: + case 0x56: + case 0x53: + case 0x2f: + case 0x5d: + case 0x5e: + return TRUE; #ifdef CONFIG_FB_SIS_315 case 0x5a: case 0x5b: if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE; #endif - } + } - if(rate < (monitor->vmin - 1)) return FALSE; - if(rate > (monitor->vmax + 1)) return FALSE; + if(rate < (monitor->vmin - 1)) + return FALSE; + if(rate > (monitor->vmax + 1)) + return FALSE; - if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext, + if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, sisbios_mode[mode_idx].mode_no[ivideo->mni], - &htotal, &vtotal, rate_idx)) { + &htotal, &vtotal, rate_idx)) { dclock = (htotal * vtotal * rate) / 1000; - if(dclock > (monitor->dclockmax + 1000)) return FALSE; + if(dclock > (monitor->dclockmax + 1000)) + return FALSE; hsync = dclock / htotal; - if(hsync < (monitor->hmin - 1)) return FALSE; - if(hsync > (monitor->hmax + 1)) return FALSE; + if(hsync < (monitor->hmin - 1)) + return FALSE; + if(hsync > (monitor->hmax + 1)) + return FALSE; } else { - return FALSE; + return FALSE; } return TRUE; } @@ -577,82 +664,79 @@ sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, static int sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags) { - u16 xres=0, yres, myres; + u16 xres=0, yres, myres; #ifdef CONFIG_FB_SIS_300 - if(ivideo->sisvga_engine == SIS_300_VGA) { - if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1); - } + if(ivideo->sisvga_engine == SIS_300_VGA) { + if(!(sisbios_mode[myindex].chipset & MD_SIS300)) + return -1 ; + } #endif #ifdef CONFIG_FB_SIS_315 - if(ivideo->sisvga_engine == SIS_315_VGA) { - if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1); - } + if(ivideo->sisvga_engine == SIS_315_VGA) { + if(!(sisbios_mode[myindex].chipset & MD_SIS315)) + return -1; + } #endif - myres = sisbios_mode[myindex].yres; + myres = sisbios_mode[myindex].yres; - switch(vbflags & VB_DISPTYPE_DISP2) { + switch(vbflags & VB_DISPTYPE_DISP2) { - case CRT2_LCD: + case CRT2_LCD: + xres = ivideo->lcdxres; yres = ivideo->lcdyres; - xres = ivideo->lcdxres; yres = ivideo->lcdyres; - - if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) { - if(sisbios_mode[myindex].xres > xres) return(-1); - if(myres > yres) return(-1); - } + if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) && + (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) { + if(sisbios_mode[myindex].xres > xres) + return -1; + if(myres > yres) + return -1; + } - if(vbflags & (VB_LVDS | VB_30xBDH)) { - if(sisbios_mode[myindex].xres == 320) { - if((myres == 240) || (myres == 480)) { - if(!ivideo->sisfb_fstn) { - if(sisbios_mode[myindex].mode_no[1] == 0x5a || - sisbios_mode[myindex].mode_no[1] == 0x5b) - return(-1); - } else { - if(sisbios_mode[myindex].mode_no[1] == 0x50 || - sisbios_mode[myindex].mode_no[1] == 0x56 || - sisbios_mode[myindex].mode_no[1] == 0x53) - return(-1); - } - } - } - } + if(ivideo->sisfb_fstn) { + if(sisbios_mode[myindex].xres == 320) { + if(myres == 240) { + switch(sisbios_mode[myindex].mode_no[1]) { + case 0x50: myindex = MODE_FSTN_8; break; + case 0x56: myindex = MODE_FSTN_16; break; + case 0x53: return -1; + } + } + } + } - if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, - sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn, - ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) { - return(-1); - } - break; + if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, + sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn, + ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) { + return -1; + } + break; - case CRT2_TV: - if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, - sisbios_mode[myindex].yres, 0) < 0x14) { - return(-1); - } - break; + case CRT2_TV: + if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, + sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) { + return -1; + } + break; - case CRT2_VGA: - if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, - sisbios_mode[myindex].yres, 0) < 0x14) { - return(-1); + case CRT2_VGA: + if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres, + sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) { + return -1; + } + break; } - break; - } - return(myindex); + return myindex; } static u8 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx) { - u16 xres, yres; int i = 0; - - xres = sisbios_mode[mode_idx].xres; - yres = sisbios_mode[mode_idx].yres; + u16 xres = sisbios_mode[mode_idx].xres; + u16 yres = sisbios_mode[mode_idx].yres; ivideo->rate_idx = 0; while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) { @@ -672,14 +756,14 @@ sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int rate, sisfb_vrate[i-1].refresh); ivideo->rate_idx = sisfb_vrate[i-1].idx; ivideo->refresh_rate = sisfb_vrate[i-1].refresh; - } + } break; } else if((rate - sisfb_vrate[i].refresh) <= 2) { DPRINTK("sisfb: Adjusting rate from %d down to %d\n", rate, sisfb_vrate[i].refresh); - ivideo->rate_idx = sisfb_vrate[i].idx; - break; - } + ivideo->rate_idx = sisfb_vrate[i].idx; + break; + } } i++; } @@ -695,252 +779,321 @@ sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int static BOOLEAN sisfb_bridgeisslave(struct sis_video_info *ivideo) { - unsigned char P1_00; + unsigned char P1_00; - if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE; + if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) + return FALSE; - inSISIDXREG(SISPART1,0x00,P1_00); - if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) || - ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) { - return TRUE; - } else { - return FALSE; - } + inSISIDXREG(SISPART1,0x00,P1_00); + if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) || + ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) { + return TRUE; + } else { + return FALSE; + } } static BOOLEAN sisfballowretracecrt1(struct sis_video_info *ivideo) { - u8 temp; + u8 temp; - inSISIDXREG(SISCR,0x17,temp); - if(!(temp & 0x80)) return FALSE; + inSISIDXREG(SISCR,0x17,temp); + if(!(temp & 0x80)) + return FALSE; - inSISIDXREG(SISSR,0x1f,temp); - if(temp & 0xc0) return FALSE; + inSISIDXREG(SISSR,0x1f,temp); + if(temp & 0xc0) + return FALSE; - return TRUE; + return TRUE; } static BOOLEAN sisfbcheckvretracecrt1(struct sis_video_info *ivideo) { - if(!sisfballowretracecrt1(ivideo)) return FALSE; + if(!sisfballowretracecrt1(ivideo)) + return FALSE; - if(inSISREG(SISINPSTAT) & 0x08) return TRUE; - else return FALSE; + if(inSISREG(SISINPSTAT) & 0x08) + return TRUE; + else + return FALSE; } static void sisfbwaitretracecrt1(struct sis_video_info *ivideo) { - int watchdog; + int watchdog; - if(!sisfballowretracecrt1(ivideo)) return; + if(!sisfballowretracecrt1(ivideo)) + return; - watchdog = 65536; - while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog); - watchdog = 65536; - while((inSISREG(SISINPSTAT) & 0x08) && --watchdog); + watchdog = 65536; + while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog); + watchdog = 65536; + while((inSISREG(SISINPSTAT) & 0x08) && --watchdog); } static BOOLEAN sisfbcheckvretracecrt2(struct sis_video_info *ivideo) { - unsigned char temp, reg; + unsigned char temp, reg; - switch(ivideo->sisvga_engine) { - case SIS_300_VGA: reg = 0x25; break; - case SIS_315_VGA: reg = 0x30; break; - default: return FALSE; - } + switch(ivideo->sisvga_engine) { + case SIS_300_VGA: reg = 0x25; break; + case SIS_315_VGA: reg = 0x30; break; + default: return FALSE; + } - inSISIDXREG(SISPART1, reg, temp); - if(temp & 0x02) return TRUE; - else return FALSE; + inSISIDXREG(SISPART1, reg, temp); + if(temp & 0x02) + return TRUE; + else + return FALSE; } static BOOLEAN sisfb_CheckVBRetrace(struct sis_video_info *ivideo) { - if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { - if(sisfb_bridgeisslave(ivideo)) { - return(sisfbcheckvretracecrt1(ivideo)); - } else { - return(sisfbcheckvretracecrt2(ivideo)); - } - } - return(sisfbcheckvretracecrt1(ivideo)); + if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { + if(!sisfb_bridgeisslave(ivideo)) { + return sisfbcheckvretracecrt2(ivideo); + } + } + return sisfbcheckvretracecrt1(ivideo); } static u32 sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount) { - u8 idx, reg1, reg2, reg3, reg4; - u32 ret = 0; - - (*vcount) = (*hcount) = 0; - - if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) { - ret |= (FB_VBLANK_HAVE_VSYNC | - FB_VBLANK_HAVE_HBLANK | - FB_VBLANK_HAVE_VBLANK | - FB_VBLANK_HAVE_VCOUNT | - FB_VBLANK_HAVE_HCOUNT); - switch(ivideo->sisvga_engine) { - case SIS_300_VGA: idx = 0x25; break; - default: - case SIS_315_VGA: idx = 0x30; break; - } - inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */ - inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */ - inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */ - inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */ - if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING; - if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING; - if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING; - (*vcount) = reg3 | ((reg4 & 0x70) << 4); - (*hcount) = reg2 | ((reg4 & 0x0f) << 8); - } else if(sisfballowretracecrt1(ivideo)) { - ret |= (FB_VBLANK_HAVE_VSYNC | - FB_VBLANK_HAVE_VBLANK | - FB_VBLANK_HAVE_VCOUNT | - FB_VBLANK_HAVE_HCOUNT); - reg1 = inSISREG(SISINPSTAT); - if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING; - if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING; - inSISIDXREG(SISCR,0x20,reg1); - inSISIDXREG(SISCR,0x1b,reg1); - inSISIDXREG(SISCR,0x1c,reg2); - inSISIDXREG(SISCR,0x1d,reg3); - (*vcount) = reg2 | ((reg3 & 0x07) << 8); - (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3; - } - return ret; + u8 idx, reg1, reg2, reg3, reg4; + u32 ret = 0; + + (*vcount) = (*hcount) = 0; + + if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) { + + ret |= (FB_VBLANK_HAVE_VSYNC | + FB_VBLANK_HAVE_HBLANK | + FB_VBLANK_HAVE_VBLANK | + FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_HCOUNT); + switch(ivideo->sisvga_engine) { + case SIS_300_VGA: idx = 0x25; break; + default: + case SIS_315_VGA: idx = 0x30; break; + } + inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */ + inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */ + inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */ + inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */ + if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING; + if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING; + if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING; + (*vcount) = reg3 | ((reg4 & 0x70) << 4); + (*hcount) = reg2 | ((reg4 & 0x0f) << 8); + + } else if(sisfballowretracecrt1(ivideo)) { + + ret |= (FB_VBLANK_HAVE_VSYNC | + FB_VBLANK_HAVE_VBLANK | + FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_HCOUNT); + reg1 = inSISREG(SISINPSTAT); + if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING; + if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING; + inSISIDXREG(SISCR,0x20,reg1); + inSISIDXREG(SISCR,0x1b,reg1); + inSISIDXREG(SISCR,0x1c,reg2); + inSISIDXREG(SISCR,0x1d,reg3); + (*vcount) = reg2 | ((reg3 & 0x07) << 8); + (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3; + } + + return ret; } static int sisfb_myblank(struct sis_video_info *ivideo, int blank) { - u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13; - BOOLEAN backlight = TRUE; - - switch(blank) { - case FB_BLANK_UNBLANK: /* on */ - sr01 = 0x00; - sr11 = 0x00; - sr1f = 0x00; - cr63 = 0x00; - p2_0 = 0x20; - p1_13 = 0x00; - backlight = TRUE; - break; - case FB_BLANK_NORMAL: /* blank */ - sr01 = 0x20; - sr11 = 0x00; - sr1f = 0x00; - cr63 = 0x00; - p2_0 = 0x20; - p1_13 = 0x00; - backlight = TRUE; - break; - case FB_BLANK_VSYNC_SUSPEND: /* no vsync */ - sr01 = 0x20; - sr11 = 0x08; - sr1f = 0x80; - cr63 = 0x40; - p2_0 = 0x40; - p1_13 = 0x80; - backlight = FALSE; - break; - case FB_BLANK_HSYNC_SUSPEND: /* no hsync */ - sr01 = 0x20; - sr11 = 0x08; - sr1f = 0x40; - cr63 = 0x40; - p2_0 = 0x80; - p1_13 = 0x40; - backlight = FALSE; - break; - case FB_BLANK_POWERDOWN: /* off */ - sr01 = 0x20; - sr11 = 0x08; - sr1f = 0xc0; - cr63 = 0x40; - p2_0 = 0xc0; - p1_13 = 0xc0; - backlight = FALSE; - break; - default: - return 1; - } - - if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) { - - if( (!ivideo->sisfb_thismonitor.datavalid) || - ((ivideo->sisfb_thismonitor.datavalid) && - (ivideo->sisfb_thismonitor.feature & 0xe0))) { - - if(ivideo->sisvga_engine == SIS_315_VGA) { - setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63); - } - - if(!(sisfb_bridgeisslave(ivideo))) { - setSISIDXREG(SISSR, 0x01, ~0x20, sr01); - setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f); - } - } - - } - - if(ivideo->currentvbflags & CRT2_LCD) { - - if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) { - if(backlight) { - SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext); - } else { - SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext); - } - } else if(ivideo->sisvga_engine == SIS_315_VGA) { - if(ivideo->vbflags & VB_CHRONTEL) { - if(backlight) { - SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext); - } else { - SiS_Chrontel701xBLOff(&ivideo->SiS_Pr); - } - } - } - - if(((ivideo->sisvga_engine == SIS_300_VGA) && - (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) || - ((ivideo->sisvga_engine == SIS_315_VGA) && - ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) { - setSISIDXREG(SISSR, 0x11, ~0x0c, sr11); - } - - if(ivideo->sisvga_engine == SIS_300_VGA) { - if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) && - (!(ivideo->vbflags & VB_30xBDH))) { - setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13); - } - } else if(ivideo->sisvga_engine == SIS_315_VGA) { - if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) && - (!(ivideo->vbflags & VB_30xBDH))) { - setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0); - } - } - - } else if(ivideo->currentvbflags & CRT2_VGA) { - - if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) { - setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0); - } - - } - - return(0); + u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13; + BOOLEAN backlight = TRUE; + + switch(blank) { + case FB_BLANK_UNBLANK: /* on */ + sr01 = 0x00; + sr11 = 0x00; + sr1f = 0x00; + cr63 = 0x00; + p2_0 = 0x20; + p1_13 = 0x00; + backlight = TRUE; + break; + case FB_BLANK_NORMAL: /* blank */ + sr01 = 0x20; + sr11 = 0x00; + sr1f = 0x00; + cr63 = 0x00; + p2_0 = 0x20; + p1_13 = 0x00; + backlight = TRUE; + break; + case FB_BLANK_VSYNC_SUSPEND: /* no vsync */ + sr01 = 0x20; + sr11 = 0x08; + sr1f = 0x80; + cr63 = 0x40; + p2_0 = 0x40; + p1_13 = 0x80; + backlight = FALSE; + break; + case FB_BLANK_HSYNC_SUSPEND: /* no hsync */ + sr01 = 0x20; + sr11 = 0x08; + sr1f = 0x40; + cr63 = 0x40; + p2_0 = 0x80; + p1_13 = 0x40; + backlight = FALSE; + break; + case FB_BLANK_POWERDOWN: /* off */ + sr01 = 0x20; + sr11 = 0x08; + sr1f = 0xc0; + cr63 = 0x40; + p2_0 = 0xc0; + p1_13 = 0xc0; + backlight = FALSE; + break; + default: + return 1; + } + + if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) { + + if( (!ivideo->sisfb_thismonitor.datavalid) || + ((ivideo->sisfb_thismonitor.datavalid) && + (ivideo->sisfb_thismonitor.feature & 0xe0))) { + + if(ivideo->sisvga_engine == SIS_315_VGA) { + setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63); + } + + if(!(sisfb_bridgeisslave(ivideo))) { + setSISIDXREG(SISSR, 0x01, ~0x20, sr01); + setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f); + } + } + + } + + if(ivideo->currentvbflags & CRT2_LCD) { + + if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) { + if(backlight) { + SiS_SiS30xBLOn(&ivideo->SiS_Pr); + } else { + SiS_SiS30xBLOff(&ivideo->SiS_Pr); + } + } else if(ivideo->sisvga_engine == SIS_315_VGA) { +#ifdef CONFIG_FB_SIS_315 + if(ivideo->vbflags2 & VB2_CHRONTEL) { + if(backlight) { + SiS_Chrontel701xBLOn(&ivideo->SiS_Pr); + } else { + SiS_Chrontel701xBLOff(&ivideo->SiS_Pr); + } + } +#endif + } + + if(((ivideo->sisvga_engine == SIS_300_VGA) && + (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) || + ((ivideo->sisvga_engine == SIS_315_VGA) && + ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) { + setSISIDXREG(SISSR, 0x11, ~0x0c, sr11); + } + + if(ivideo->sisvga_engine == SIS_300_VGA) { + if((ivideo->vbflags2 & VB2_30xB) && + (!(ivideo->vbflags2 & VB2_30xBDH))) { + setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13); + } + } else if(ivideo->sisvga_engine == SIS_315_VGA) { + if((ivideo->vbflags2 & VB2_30xB) && + (!(ivideo->vbflags2 & VB2_30xBDH))) { + setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0); + } + } + + } else if(ivideo->currentvbflags & CRT2_VGA) { + + if(ivideo->vbflags2 & VB2_30xB) { + setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0); + } + + } + + return 0; +} + +/* ------------- Callbacks from init.c/init301.c -------------- */ + +#ifdef CONFIG_FB_SIS_300 +unsigned int +sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo; + u32 val = 0; + + pci_read_config_dword(ivideo->nbridge, reg, &val); + return (unsigned int)val; +} + +void +sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo; + + pci_write_config_dword(ivideo->nbridge, reg, (u32)val); +} + +unsigned int +sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo; + u32 val = 0; + + if(!ivideo->lpcdev) return 0; + + pci_read_config_dword(ivideo->lpcdev, reg, &val); + return (unsigned int)val; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +void +sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo; + + pci_write_config_byte(ivideo->nbridge, reg, (u8)val); } +unsigned int +sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg) +{ + struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo; + u16 val = 0; + + if(!ivideo->lpcdev) return 0; + + pci_read_config_word(ivideo->lpcdev, reg, &val); + return (unsigned int)val; +} +#endif + /* ----------- FBDev related routines for all series ----------- */ static int @@ -952,7 +1105,7 @@ sisfb_get_cmap_len(const struct fb_var_screeninfo *var) static void sisfb_set_vparms(struct sis_video_info *ivideo) { - switch(ivideo->video_bpp) { + switch(ivideo->video_bpp) { case 8: ivideo->DstColor = 0x0000; ivideo->SiS310_AccelDepth = 0x00000000; @@ -972,14 +1125,13 @@ sisfb_set_vparms(struct sis_video_info *ivideo) ivideo->video_cmap_len = 16; printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp); ivideo->accel = 0; - break; - } + } } static int sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) { - int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3)); + int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3)); if(maxyres > 32767) maxyres = 32767; @@ -996,30 +1148,29 @@ sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) ivideo->scrnpitchCRT1 <<= 1; } } - } static void sisfb_set_pitch(struct sis_video_info *ivideo) { - BOOLEAN isslavemode = FALSE; + BOOLEAN isslavemode = FALSE; unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3; unsigned short HDisplay2 = ivideo->video_linelength >> 3; - if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE; + if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE; - /* We need to set pitch for CRT1 if bridge is in slave mode, too */ - if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) { - outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF)); - setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8)); + /* We need to set pitch for CRT1 if bridge is in slave mode, too */ + if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) { + outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF)); + setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8)); } - /* We must not set the pitch for CRT2 if bridge is in slave mode */ - if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) { + /* We must not set the pitch for CRT2 if bridge is in slave mode */ + if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) { orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01); - outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF)); - setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8)); - } + outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF)); + setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8)); + } } static void @@ -1055,13 +1206,42 @@ sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) } } +static int +sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn) +{ + unsigned short modeno = ivideo->mode_no; + + /* >=2.6.12's fbcon clears the screen anyway */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) + if(!clrscrn) modeno |= 0x80; +#else + modeno |= 0x80; +#endif + + outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); + + sisfb_pre_setmode(ivideo); + + if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) { + printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no); + return -EINVAL; + } + + outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); + + sisfb_post_setmode(ivideo); + + return 0; +} + + static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info) { struct sis_video_info *ivideo = (struct sis_video_info *)info->par; unsigned int htotal = 0, vtotal = 0; unsigned int drate = 0, hrate = 0; - int found_mode = 0; + int found_mode = 0, ret; int old_mode; u32 pixclock; @@ -1088,11 +1268,11 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in } if(pixclock && htotal && vtotal) { - drate = 1000000000 / pixclock; - hrate = (drate * 1000) / htotal; - ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal); + drate = 1000000000 / pixclock; + hrate = (drate * 1000) / htotal; + ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal); } else { - ivideo->refresh_rate = 60; + ivideo->refresh_rate = 60; } old_mode = ivideo->sisfb_mode_idx; @@ -1113,6 +1293,7 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in if(found_mode) { ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo, ivideo->sisfb_mode_idx, ivideo->currentvbflags); + ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]; } else { ivideo->sisfb_mode_idx = -1; } @@ -1131,10 +1312,10 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) if(ivideo->sisfb_thismonitor.datavalid) { - if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx, + if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx, ivideo->rate_idx, ivideo->refresh_rate)) { - printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); - } + printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); + } } #endif @@ -1143,24 +1324,9 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in #else if(isactive) { #endif - sisfb_pre_setmode(ivideo); - - if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) { - printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no); - return -EINVAL; - } - - outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); - - sisfb_post_setmode(ivideo); - - ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp; - ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres; - ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres; - - sisfb_calc_pitch(ivideo, var); - sisfb_set_pitch(ivideo); - + /* If acceleration to be used? Need to know + * before pre/post_set_mode() + */ ivideo->accel = 0; #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN) #ifdef STUPID_ACCELF_TEXT_SHIT @@ -1175,6 +1341,17 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1; #endif + if((ret = sisfb_set_mode(ivideo, 1))) { + return ret; + } + + ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp; + ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres; + ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres; + + sisfb_calc_pitch(ivideo, var); + sisfb_set_pitch(ivideo); + sisfb_set_vparms(ivideo); ivideo->current_width = ivideo->video_width; @@ -1186,823 +1363,342 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in ivideo->current_pixclock = var->pixclock; ivideo->current_refresh_rate = ivideo->refresh_rate; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate; + ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate; #endif } return 0; } -static int -sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +static void +sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base) { - unsigned int base; - - if(var->xoffset > (var->xres_virtual - var->xres)) { - return -EINVAL; - } - if(var->yoffset > (var->yres_virtual - var->yres)) { - return -EINVAL; - } - - base = (var->yoffset * var->xres_virtual) + var->xoffset; - - /* calculate base bpp dep. */ - switch(var->bits_per_pixel) { - case 32: - break; - case 16: - base >>= 1; - break; - case 8: - default: - base >>= 2; - break; - } - outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); - outSISIDXREG(SISCR, 0x0D, base & 0xFF); + outSISIDXREG(SISCR, 0x0D, base & 0xFF); outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF); outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF); if(ivideo->sisvga_engine == SIS_315_VGA) { setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01); } - if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { +} + +static void +sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base) +{ + if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01); - outSISIDXREG(SISPART1, 0x06, (base & 0xFF)); - outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF)); - outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF)); + outSISIDXREG(SISPART1, 0x06, (base & 0xFF)); + outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF)); + outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF)); if(ivideo->sisvga_engine == SIS_315_VGA) { setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7); } - } - return 0; + } } -/* ------------ FBDev related routines for 2.4 series ----------- */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - -static void -sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +static int +sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) { - u16 VRE, VBE, VRS, VBS, VDE, VT; - u16 HRE, HBE, HRS, HBS, HDE, HT; - u8 sr_data, cr_data, cr_data2, cr_data3, mr_data; - int A, B, C, D, E, F, temp; - unsigned int hrate, drate, maxyres; - - inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data); + if(var->xoffset > (var->xres_virtual - var->xres)) { + return -EINVAL; + } + if(var->yoffset > (var->yres_virtual - var->yres)) { + return -EINVAL; + } - if(sr_data & SIS_INTERLACED_MODE) - var->vmode = FB_VMODE_INTERLACED; - else - var->vmode = FB_VMODE_NONINTERLACED; + ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset; - switch((sr_data & 0x1C) >> 2) { - case SIS_8BPP_COLOR_MODE: - var->bits_per_pixel = 8; + /* calculate base bpp dep. */ + switch(var->bits_per_pixel) { + case 32: break; - case SIS_16BPP_COLOR_MODE: - var->bits_per_pixel = 16; + case 16: + ivideo->current_base >>= 1; break; - case SIS_32BPP_COLOR_MODE: - var->bits_per_pixel = 32; + case 8: + default: + ivideo->current_base >>= 2; break; } - sisfb_bpp_to_var(ivideo, var); - - inSISIDXREG(SISSR, 0x0A, sr_data); - inSISIDXREG(SISCR, 0x06, cr_data); - inSISIDXREG(SISCR, 0x07, cr_data2); - - VT = (cr_data & 0xFF) | - ((u16) (cr_data2 & 0x01) << 8) | - ((u16) (cr_data2 & 0x20) << 4) | - ((u16) (sr_data & 0x01) << 10); - A = VT + 2; - - inSISIDXREG(SISCR, 0x12, cr_data); - - VDE = (cr_data & 0xff) | - ((u16) (cr_data2 & 0x02) << 7) | - ((u16) (cr_data2 & 0x40) << 3) | - ((u16) (sr_data & 0x02) << 9); - E = VDE + 1; - - inSISIDXREG(SISCR, 0x10, cr_data); - - VRS = (cr_data & 0xff) | - ((u16) (cr_data2 & 0x04) << 6) | - ((u16) (cr_data2 & 0x80) << 2) | - ((u16) (sr_data & 0x08) << 7); - F = VRS + 1 - E; - - inSISIDXREG(SISCR, 0x15, cr_data); - inSISIDXREG(SISCR, 0x09, cr_data3); - - if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE; - - VBS = (cr_data & 0xff) | - ((u16) (cr_data2 & 0x08) << 5) | - ((u16) (cr_data3 & 0x20) << 4) | - ((u16) (sr_data & 0x04) << 8); - - inSISIDXREG(SISCR, 0x16, cr_data); - - VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4); - temp = VBE - ((E - 1) & 511); - B = (temp > 0) ? temp : (temp + 512); - - inSISIDXREG(SISCR, 0x11, cr_data); - - VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); - temp = VRE - ((E + F - 1) & 31); - C = (temp > 0) ? temp : (temp + 32); - - D = B - F - C; - - var->yres = E; - var->upper_margin = D; - var->lower_margin = F; - var->vsync_len = C; - - if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { - var->yres <<= 1; - var->upper_margin <<= 1; - var->lower_margin <<= 1; - var->vsync_len <<= 1; - } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { - var->yres >>= 1; - var->upper_margin >>= 1; - var->lower_margin >>= 1; - var->vsync_len >>= 1; - } - - inSISIDXREG(SISSR, 0x0b, sr_data); - inSISIDXREG(SISCR, 0x00, cr_data); - - HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8); - A = HT + 5; - - inSISIDXREG(SISCR, 0x01, cr_data); - - HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6); - E = HDE + 1; - - inSISIDXREG(SISCR, 0x04, cr_data); - - HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2); - F = HRS - E - 3; - - inSISIDXREG(SISCR, 0x02, cr_data); + ivideo->current_base += (ivideo->video_offset >> 2); - HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4); + sisfb_set_base_CRT1(ivideo, ivideo->current_base); + sisfb_set_base_CRT2(ivideo, ivideo->current_base); - inSISIDXREG(SISSR, 0x0c, sr_data); - inSISIDXREG(SISCR, 0x03, cr_data); - inSISIDXREG(SISCR, 0x05, cr_data2); - - HBE = (cr_data & 0x1f) | - ((u16) (cr_data2 & 0x80) >> 2) | - ((u16) (sr_data & 0x03) << 6); - HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3); - - temp = HBE - ((E - 1) & 255); - B = (temp > 0) ? temp : (temp + 256); - - temp = HRE - ((E + F + 3) & 63); - C = (temp > 0) ? temp : (temp + 64); - - D = B - F - C; - - var->xres = E * 8; - if(var->xres_virtual < var->xres) { - var->xres_virtual = var->xres; - } - - if((var->xres == 320) && - (var->yres == 200 || var->yres == 240)) { - /* Terrible hack, but the correct CRTC data for - * these modes only produces a black screen... - */ - var->left_margin = (400 - 376); - var->right_margin = (328 - 320); - var->hsync_len = (376 - 328); - } else { - var->left_margin = D * 8; - var->right_margin = F * 8; - var->hsync_len = C * 8; - } - var->activate = FB_ACTIVATE_NOW; + return 0; +} - var->sync = 0; +/* ------------ FBDev related routines for 2.4 series ----------- */ - mr_data = inSISREG(SISMISCR); - if(mr_data & 0x80) - var->sync &= ~FB_SYNC_VERT_HIGH_ACT; - else - var->sync |= FB_SYNC_VERT_HIGH_ACT; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - if(mr_data & 0x40) - var->sync &= ~FB_SYNC_HOR_HIGH_ACT; - else - var->sync |= FB_SYNC_HOR_HIGH_ACT; +#include "sisfb_fbdev_2_4.h" - VT += 2; - VT <<= 1; - HT = (HT + 5) * 8; +#endif - if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { - VT <<= 1; - } - hrate = ivideo->refresh_rate * VT / 2; - drate = (hrate * HT) / 1000; - var->pixclock = (u32) (1000000000 / drate); +/* ------------ FBDev related routines for 2.6 series ----------- */ - if(ivideo->sisfb_ypan) { - maxyres = sisfb_calc_maxyres(ivideo, var); - if(ivideo->sisfb_max) { - var->yres_virtual = maxyres; - } else { - if(var->yres_virtual > maxyres) { - var->yres_virtual = maxyres; - } - } - if(var->yres_virtual <= var->yres) { - var->yres_virtual = var->yres; - } - } else { - var->yres_virtual = var->yres; - } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static int +sisfb_open(struct fb_info *info, int user) +{ + return 0; } static int -sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, - unsigned *transp, struct fb_info *info) +sisfb_release(struct fb_info *info, int user) { - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - - if(regno >= ivideo->video_cmap_len) return 1; - - *red = ivideo->sis_palette[regno].red; - *green = ivideo->sis_palette[regno].green; - *blue = ivideo->sis_palette[regno].blue; - *transp = 0; - return 0; } static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, - unsigned transp, struct fb_info *info) + unsigned transp, struct fb_info *info) { struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - if(regno >= ivideo->video_cmap_len) return 1; - - ivideo->sis_palette[regno].red = red; - ivideo->sis_palette[regno].green = green; - ivideo->sis_palette[regno].blue = blue; + if(regno >= sisfb_get_cmap_len(&info->var)) + return 1; - switch(ivideo->video_bpp) { -#ifdef FBCON_HAS_CFB8 + switch(info->var.bits_per_pixel) { case 8: - outSISREG(SISDACA, regno); + outSISREG(SISDACA, regno); outSISREG(SISDACD, (red >> 10)); outSISREG(SISDACD, (green >> 10)); outSISREG(SISDACD, (blue >> 10)); if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { - outSISREG(SISDAC2A, regno); + outSISREG(SISDAC2A, regno); outSISREG(SISDAC2D, (red >> 8)); outSISREG(SISDAC2D, (green >> 8)); outSISREG(SISDAC2D, (blue >> 8)); } break; -#endif -#ifdef FBCON_HAS_CFB16 case 16: - ivideo->sis_fbcon_cmap.cfb16[regno] = - ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + ((u32 *)(info->pseudo_palette))[regno] = + (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); break; -#endif -#ifdef FBCON_HAS_CFB32 case 32: - red >>= 8; + red >>= 8; green >>= 8; - blue >>= 8; - ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue); + blue >>= 8; + ((u32 *)(info->pseudo_palette))[regno] = + (red << 16) | (green << 8) | (blue); break; -#endif } - return 0; } -static void -sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - struct display *display; - struct display_switch *sw; - struct fb_fix_screeninfo fix; - long flags; - - display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp; - - sisfb_get_fix(&fix, con, info); - - display->var = *var; - display->screen_base = (char *)ivideo->video_vbase; - display->visual = fix.visual; - display->type = fix.type; - display->type_aux = fix.type_aux; - display->ypanstep = fix.ypanstep; - display->ywrapstep = fix.ywrapstep; - display->line_length = fix.line_length; - display->can_soft_blank = 1; - display->inverse = ivideo->sisfb_inverse; - display->next_line = fix.line_length; - - save_flags(flags); - - switch(ivideo->video_bpp) { -#ifdef FBCON_HAS_CFB8 - case 8: sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16:sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16; - display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32:sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32; - display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32; - break; -#endif - default:sw = &fbcon_dummy; - break; - } - memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw)); - display->dispsw = &ivideo->sisfb_sw; - - restore_flags(flags); - - if(ivideo->sisfb_ypan) { - /* display->scrollmode = 0; */ - } else { - display->scrollmode = SCROLL_YREDRAW; - ivideo->sisfb_sw.bmove = fbcon_redraw_bmove; - } -} - -static void -sisfb_do_install_cmap(int con, struct fb_info *info) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - - if(con != ivideo->currcon) return; - - if(fb_display[con].cmap.len) { - fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info); - } else { - int size = sisfb_get_cmap_len(&fb_display[con].var); - fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info); - } -} - static int -sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) +sisfb_set_par(struct fb_info *info) { - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - - if(con == -1) { - memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo)); - } else { - *var = fb_display[con].var; - } + int err; - if(ivideo->sisfb_fstn) { - if(var->xres == 320 && var->yres == 480) var->yres = 240; - } + if((err = sisfb_do_set_var(&info->var, 1, info))) + return err; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + sisfb_get_fix(&info->fix, info->currcon, info); +#else + sisfb_get_fix(&info->fix, -1, info); +#endif return 0; } static int -sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) +sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - int err; + unsigned int htotal = 0, vtotal = 0, myrateindex = 0; + unsigned int drate = 0, hrate = 0, maxyres; + int found_mode = 0; + int refresh_rate, search_idx, tidx; + BOOLEAN recalc_clock = FALSE; + u32 pixclock; - fb_display[con].var.activate = FB_ACTIVATE_NOW; + htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; - if(sisfb_do_set_var(var, con == ivideo->currcon, info)) { - sisfb_crtc_to_var(ivideo, var); - return -EINVAL; - } + vtotal = var->upper_margin + var->lower_margin + var->vsync_len; - sisfb_crtc_to_var(ivideo, var); + pixclock = var->pixclock; - sisfb_set_disp(con, var, info); + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { + vtotal += var->yres; + vtotal <<= 1; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + vtotal += var->yres; + vtotal <<= 2; + } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + vtotal += var->yres; + vtotal <<= 1; + } else + vtotal += var->yres; - if(info->changevar) { - (*info->changevar)(con); + if(!(htotal) || !(vtotal)) { + SISFAIL("sisfb: no valid timing data"); } - if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) { - return err; + search_idx = 0; + while( (sisbios_mode[search_idx].mode_no[0] != 0) && + (sisbios_mode[search_idx].xres <= var->xres) ) { + if( (sisbios_mode[search_idx].xres == var->xres) && + (sisbios_mode[search_idx].yres == var->yres) && + (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) { + if((tidx = sisfb_validate_mode(ivideo, search_idx, + ivideo->currentvbflags)) > 0) { + found_mode = 1; + search_idx = tidx; + break; + } + } + search_idx++; } - sisfb_do_install_cmap(con, info); + if(!found_mode) { + search_idx = 0; + while(sisbios_mode[search_idx].mode_no[0] != 0) { + if( (var->xres <= sisbios_mode[search_idx].xres) && + (var->yres <= sisbios_mode[search_idx].yres) && + (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) { + if((tidx = sisfb_validate_mode(ivideo,search_idx, + ivideo->currentvbflags)) > 0) { + found_mode = 1; + search_idx = tidx; + break; + } + } + search_idx++; + } + if(found_mode) { + printk(KERN_DEBUG + "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n", + var->xres, var->yres, var->bits_per_pixel, + sisbios_mode[search_idx].xres, + sisbios_mode[search_idx].yres, + var->bits_per_pixel); + var->xres = sisbios_mode[search_idx].xres; + var->yres = sisbios_mode[search_idx].yres; + } else { + printk(KERN_ERR + "sisfb: Failed to find supported mode near %dx%dx%d\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + } -#if 0 /* Why was this called here? */ - unsigned int cols, rows; - cols = sisbios_mode[ivideo->sisfb_mode_idx].cols; - rows = sisbios_mode[ivideo->sisfb_mode_idx].rows; - vc_resize_con(rows, cols, fb_display[con].conp->vc_num); -#endif - return 0; -} + if( ((ivideo->vbflags2 & VB2_LVDS) || + ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) && + (var->bits_per_pixel == 8) ) { + /* Slave modes on LVDS and 301B-DH */ + refresh_rate = 60; + recalc_clock = TRUE; + } else if( (ivideo->current_htotal == htotal) && + (ivideo->current_vtotal == vtotal) && + (ivideo->current_pixclock == pixclock) ) { + /* x=x & y=y & c=c -> assume depth change */ + drate = 1000000000 / pixclock; + hrate = (drate * 1000) / htotal; + refresh_rate = (unsigned int) (hrate * 2 / vtotal); + } else if( ( (ivideo->current_htotal != htotal) || + (ivideo->current_vtotal != vtotal) ) && + (ivideo->current_pixclock == var->pixclock) ) { + /* x!=x | y!=y & c=c -> invalid pixclock */ + if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) { + refresh_rate = + ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]; + } else if(ivideo->sisfb_parm_rate != -1) { + /* Sic, sisfb_parm_rate - want to know originally desired rate here */ + refresh_rate = ivideo->sisfb_parm_rate; + } else { + refresh_rate = 60; + } + recalc_clock = TRUE; + } else if((pixclock) && (htotal) && (vtotal)) { + drate = 1000000000 / pixclock; + hrate = (drate * 1000) / htotal; + refresh_rate = (unsigned int) (hrate * 2 / vtotal); + } else if(ivideo->current_refresh_rate) { + refresh_rate = ivideo->current_refresh_rate; + recalc_clock = TRUE; + } else { + refresh_rate = 60; + recalc_clock = TRUE; + } -static int -sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - struct display *display; + myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx); - display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp; + /* Eventually recalculate timing and clock */ + if(recalc_clock) { + if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx; + var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, + sisbios_mode[search_idx].mode_no[ivideo->mni], + myrateindex)); + sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, + sisbios_mode[search_idx].mode_no[ivideo->mni], + myrateindex, var); + if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + var->pixclock <<= 1; + } + } - if(con == ivideo->currcon) { + if(ivideo->sisfb_thismonitor.datavalid) { + if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx, + myrateindex, refresh_rate)) { + printk(KERN_INFO + "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); + } + } - return fb_get_cmap(cmap, kspc, sis_getcolreg, info); + /* Adapt RGB settings */ + sisfb_bpp_to_var(ivideo, var); - } else if(display->cmap.len) { - - fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2); - - } else { - - int size = sisfb_get_cmap_len(&display->var); - fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); - - } - - return 0; -} - -static int -sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - struct display *display; - int err, size; - - display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp; - - size = sisfb_get_cmap_len(&display->var); - if(display->cmap.len != size) { - err = fb_alloc_cmap(&display->cmap, size, 0); - if(err) return err; - } - - if(con == ivideo->currcon) { - return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info); - } else { - fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1); - } - - return 0; -} - -static int -sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - int err; - - if(var->vmode & FB_VMODE_YWRAP) return -EINVAL; - - if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) || - (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) { - return -EINVAL; - } - - if(con == ivideo->currcon) { - if((err = sisfb_pan_var(ivideo, var)) < 0) return err; - } - - fb_display[con].var.xoffset = var->xoffset; - fb_display[con].var.yoffset = var->yoffset; - - return 0; -} - -static int -sisfb_update_var(int con, struct fb_info *info) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - - return(sisfb_pan_var(ivideo, &fb_display[con].var)); -} - -static int -sisfb_switch(int con, struct fb_info *info) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - int cols, rows; - - if(fb_display[ivideo->currcon].cmap.len) { - fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info); - } - - fb_display[con].var.activate = FB_ACTIVATE_NOW; - - if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var, - sizeof(struct fb_var_screeninfo))) { - ivideo->currcon = con; - return 1; - } - - ivideo->currcon = con; - - sisfb_do_set_var(&fb_display[con].var, 1, info); - - sisfb_set_disp(con, &fb_display[con].var, info); - - sisfb_do_install_cmap(con, info); - - cols = sisbios_mode[ivideo->sisfb_mode_idx].cols; - rows = sisbios_mode[ivideo->sisfb_mode_idx].rows; - vc_resize_con(rows, cols, fb_display[con].conp->vc_num); - - sisfb_update_var(con, info); - - return 1; -} - -static void -sisfb_blank(int blank, struct fb_info *info) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - - sisfb_myblank(ivideo, blank); -} -#endif - -/* ------------ FBDev related routines for 2.6 series ----------- */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - -static int -sisfb_open(struct fb_info *info, int user) -{ - return 0; -} - -static int -sisfb_release(struct fb_info *info, int user) -{ - return 0; -} - -static int -sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, - unsigned transp, struct fb_info *info) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - - if(regno >= sisfb_get_cmap_len(&info->var)) return 1; - - switch(info->var.bits_per_pixel) { - case 8: - outSISREG(SISDACA, regno); - outSISREG(SISDACD, (red >> 10)); - outSISREG(SISDACD, (green >> 10)); - outSISREG(SISDACD, (blue >> 10)); - if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { - outSISREG(SISDAC2A, regno); - outSISREG(SISDAC2D, (red >> 8)); - outSISREG(SISDAC2D, (green >> 8)); - outSISREG(SISDAC2D, (blue >> 8)); - } - break; - case 16: - ((u32 *)(info->pseudo_palette))[regno] = - ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); - break; - case 32: - red >>= 8; - green >>= 8; - blue >>= 8; - ((u32 *)(info->pseudo_palette))[regno] = - (red << 16) | (green << 8) | (blue); - break; - } - return 0; -} - -static int -sisfb_set_par(struct fb_info *info) -{ - int err; - - if((err = sisfb_do_set_var(&info->var, 1, info))) { - return err; - } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) - sisfb_get_fix(&info->fix, info->currcon, info); -#else - sisfb_get_fix(&info->fix, -1, info); -#endif - return 0; -} - -static int -sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - unsigned int htotal = 0, vtotal = 0, myrateindex = 0; - unsigned int drate = 0, hrate = 0, maxyres; - int found_mode = 0; - int refresh_rate, search_idx; - BOOLEAN recalc_clock = FALSE; - u32 pixclock; - - htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; - - vtotal = var->upper_margin + var->lower_margin + var->vsync_len; - - pixclock = var->pixclock; - - if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { - vtotal += var->yres; - vtotal <<= 1; - } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { - vtotal += var->yres; - vtotal <<= 2; - } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { - vtotal += var->yres; - vtotal <<= 1; - } else vtotal += var->yres; - - if(!(htotal) || !(vtotal)) { - SISFAIL("sisfb: no valid timing data"); - } - - search_idx = 0; - while( (sisbios_mode[search_idx].mode_no[0] != 0) && - (sisbios_mode[search_idx].xres <= var->xres) ) { - if( (sisbios_mode[search_idx].xres == var->xres) && - (sisbios_mode[search_idx].yres == var->yres) && - (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) { - if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) { - found_mode = 1; - break; - } - } - search_idx++; - } - - if(!found_mode) { - search_idx = 0; - while(sisbios_mode[search_idx].mode_no[0] != 0) { - if( (var->xres <= sisbios_mode[search_idx].xres) && - (var->yres <= sisbios_mode[search_idx].yres) && - (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) { - if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) { - found_mode = 1; - break; - } - } - search_idx++; - } - if(found_mode) { - printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n", - var->xres, var->yres, var->bits_per_pixel, - sisbios_mode[search_idx].xres, - sisbios_mode[search_idx].yres, - var->bits_per_pixel); - var->xres = sisbios_mode[search_idx].xres; - var->yres = sisbios_mode[search_idx].yres; + /* Sanity check for offsets */ + if(var->xoffset < 0) var->xoffset = 0; + if(var->yoffset < 0) var->yoffset = 0; + if(var->xres > var->xres_virtual) + var->xres_virtual = var->xres; + if(ivideo->sisfb_ypan) { + maxyres = sisfb_calc_maxyres(ivideo, var); + if(ivideo->sisfb_max) { + var->yres_virtual = maxyres; } else { - printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n", - var->xres, var->yres, var->bits_per_pixel); - return -EINVAL; + if(var->yres_virtual > maxyres) { + var->yres_virtual = maxyres; + } } - } - - if( ((ivideo->vbflags & VB_LVDS) || /* Slave modes on LVDS and 301B-DH */ - ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) && - (var->bits_per_pixel == 8) ) { - refresh_rate = 60; - recalc_clock = TRUE; - } else if( (ivideo->current_htotal == htotal) && /* x=x & y=y & c=c -> assume depth change */ - (ivideo->current_vtotal == vtotal) && - (ivideo->current_pixclock == pixclock) ) { - drate = 1000000000 / pixclock; - hrate = (drate * 1000) / htotal; - refresh_rate = (unsigned int) (hrate * 2 / vtotal); - } else if( ( (ivideo->current_htotal != htotal) || /* x!=x | y!=y & c=c -> invalid pixclock */ - (ivideo->current_vtotal != vtotal) ) && - (ivideo->current_pixclock == var->pixclock) ) { - if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) { - refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]; - } else if(ivideo->sisfb_parm_rate != -1) { - /* Sic, sisfb_parm_rate - want to know originally desired rate here */ - refresh_rate = ivideo->sisfb_parm_rate; - } else { - refresh_rate = 60; + if(var->yres_virtual <= var->yres) { + var->yres_virtual = var->yres; } - recalc_clock = TRUE; - } else if((pixclock) && (htotal) && (vtotal)) { - drate = 1000000000 / pixclock; - hrate = (drate * 1000) / htotal; - refresh_rate = (unsigned int) (hrate * 2 / vtotal); - } else if(ivideo->current_refresh_rate) { - refresh_rate = ivideo->current_refresh_rate; - recalc_clock = TRUE; } else { - refresh_rate = 60; - recalc_clock = TRUE; - } - - myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx); - - /* Eventually recalculate timing and clock */ - if(recalc_clock) { - if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx; - var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, - &ivideo->sishw_ext, - sisbios_mode[search_idx].mode_no[ivideo->mni], - myrateindex)); - sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext, - sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var); - if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { - var->pixclock <<= 1; - } - } - - if(ivideo->sisfb_thismonitor.datavalid) { - if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx, - myrateindex, refresh_rate)) { - printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); - } - } - - /* Adapt RGB settings */ - sisfb_bpp_to_var(ivideo, var); - - /* Sanity check for offsets */ - if(var->xoffset < 0) var->xoffset = 0; - if(var->yoffset < 0) var->yoffset = 0; - - if(var->xres > var->xres_virtual) { - var->xres_virtual = var->xres; + if(var->yres != var->yres_virtual) { + var->yres_virtual = var->yres; + } + var->xoffset = 0; + var->yoffset = 0; } - if(ivideo->sisfb_ypan) { - maxyres = sisfb_calc_maxyres(ivideo, var); - if(ivideo->sisfb_max) { - var->yres_virtual = maxyres; - } else { - if(var->yres_virtual > maxyres) { - var->yres_virtual = maxyres; - } - } - if(var->yres_virtual <= var->yres) { - var->yres_virtual = var->yres; - } - } else { - if(var->yres != var->yres_virtual) { - var->yres_virtual = var->yres; - } - var->xoffset = 0; - var->yoffset = 0; - } - /* Truncate offsets to maximum if too high */ if(var->xoffset > var->xres_virtual - var->xres) { - var->xoffset = var->xres_virtual - var->xres - 1; + var->xoffset = var->xres_virtual - var->xres - 1; } if(var->yoffset > var->yres_virtual - var->yres) { - var->yoffset = var->yres_virtual - var->yres - 1; + var->yoffset = var->yres_virtual - var->yres - 1; } - + /* Set everything else to 0 */ - var->red.msb_right = - var->green.msb_right = - var->blue.msb_right = - var->transp.offset = - var->transp.length = - var->transp.msb_right = 0; + var->red.msb_right = + var->green.msb_right = + var->blue.msb_right = + var->transp.offset = + var->transp.length = + var->transp.msb_right = 0; return 0; } @@ -2013,21 +1709,21 @@ sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info) struct sis_video_info *ivideo = (struct sis_video_info *)info->par; int err; - if(var->xoffset > (var->xres_virtual - var->xres)) { + if(var->xoffset > (var->xres_virtual - var->xres)) return -EINVAL; - } - if(var->yoffset > (var->yres_virtual - var->yres)) { + + if(var->yoffset > (var->yres_virtual - var->yres)) return -EINVAL; - } - if(var->vmode & FB_VMODE_YWRAP) return -EINVAL; + if(var->vmode & FB_VMODE_YWRAP) + return -EINVAL; if(var->xoffset + info->var.xres > info->var.xres_virtual || - var->yoffset + info->var.yres > info->var.yres_virtual) { + var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; - } - if((err = sisfb_pan_var(ivideo, var)) < 0) return err; + if((err = sisfb_pan_var(ivideo, var)) < 0) + return err; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; @@ -2040,7 +1736,7 @@ sisfb_blank(int blank, struct fb_info *info) { struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - return(sisfb_myblank(ivideo, blank)); + return sisfb_myblank(ivideo, blank); } #endif @@ -2056,153 +1752,184 @@ sisfb_ioctl(struct inode *inode, struct file *file, struct fb_info *info) { struct sis_video_info *ivideo = (struct sis_video_info *)info->par; - struct sis_memreq sismemreq; - struct fb_vblank sisvbblank; - sisfb_info x; + struct sis_memreq sismemreq; + struct fb_vblank sisvbblank; u32 gpu32 = 0; #ifndef __user #define __user #endif u32 __user *argp = (u32 __user *)arg; - switch (cmd) { + switch(cmd) { case FBIO_ALLOC: - if(!capable(CAP_SYS_RAWIO)) { + if(!capable(CAP_SYS_RAWIO)) return -EPERM; - } - if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) { - return -EFAULT; - } + + if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) + return -EFAULT; + sis_malloc(&sismemreq); + if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) { sis_free((u32)sismemreq.offset); - return -EFAULT; + return -EFAULT; } break; case FBIO_FREE: - if(!capable(CAP_SYS_RAWIO)) { + if(!capable(CAP_SYS_RAWIO)) return -EPERM; - } - if(get_user(gpu32, argp)) { + + if(get_user(gpu32, argp)) return -EFAULT; - } + sis_free(gpu32); break; case FBIOGET_VBLANK: sisvbblank.count = 0; sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount); - if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) { + + if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) return -EFAULT; - } + break; case SISFB_GET_INFO_SIZE: - return put_user(sizeof(sisfb_info), argp); + return put_user(sizeof(struct sisfb_info), argp); case SISFB_GET_INFO_OLD: - if(ivideo->warncount++ < 50) { - printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); - } + if(ivideo->warncount++ < 10) + printk(KERN_INFO + "sisfb: Deprecated ioctl call received - update your application!\n"); case SISFB_GET_INFO: /* For communication with X driver */ - x.sisfb_id = SISFB_ID; - x.sisfb_version = VER_MAJOR; - x.sisfb_revision = VER_MINOR; - x.sisfb_patchlevel = VER_LEVEL; - x.chip_id = ivideo->chip_id; - x.memory = ivideo->video_size / 1024; - x.heapstart = ivideo->heapstart / 1024; + ivideo->sisfb_infoblock.sisfb_id = SISFB_ID; + ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR; + ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR; + ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL; + ivideo->sisfb_infoblock.chip_id = ivideo->chip_id; + ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor; + ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024; + ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024; if(ivideo->modechanged) { - x.fbvidmode = ivideo->mode_no; + ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no; } else { - x.fbvidmode = ivideo->modeprechange; - } - x.sisfb_caps = ivideo->caps; - x.sisfb_tqlen = 512; /* yet fixed */ - x.sisfb_pcibus = ivideo->pcibus; - x.sisfb_pcislot = ivideo->pcislot; - x.sisfb_pcifunc = ivideo->pcifunc; - x.sisfb_lcdpdc = ivideo->detectedpdc; - x.sisfb_lcdpdca = ivideo->detectedpdca; - x.sisfb_lcda = ivideo->detectedlcda; - x.sisfb_vbflags = ivideo->vbflags; - x.sisfb_currentvbflags = ivideo->currentvbflags; - x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler; - x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT; - x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0; - x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0; - x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30; - x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31; - x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32; - x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33; - x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32); - x.sisfb_tvypos = (u16)(ivideo->tvypos + 32); - - if(copy_to_user((void __user *)arg, &x, sizeof(x))) { - return -EFAULT; + ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange; } + ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps; + ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024; + ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus; + ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot; + ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc; + ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc; + ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca; + ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda; + ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags; + ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags; + ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler; + ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT; + ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0; + ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0; + ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30; + ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31; + ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32; + ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33; + ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32); + ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32); + ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024; + ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset; + ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN; + ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN; + ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2; + ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0; + ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0; + ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0; + + if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock, + sizeof(ivideo->sisfb_infoblock))) + return -EFAULT; + break; case SISFB_GET_VBRSTATUS_OLD: - if(ivideo->warncount++ < 50) { - printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); - } + if(ivideo->warncount++ < 10) + printk(KERN_INFO + "sisfb: Deprecated ioctl call received - update your application!\n"); case SISFB_GET_VBRSTATUS: - if(sisfb_CheckVBRetrace(ivideo)) { + if(sisfb_CheckVBRetrace(ivideo)) return put_user((u32)1, argp); - } else { + else return put_user((u32)0, argp); - } case SISFB_GET_AUTOMAXIMIZE_OLD: - if(ivideo->warncount++ < 50) { - printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); - } + if(ivideo->warncount++ < 10) + printk(KERN_INFO + "sisfb: Deprecated ioctl call received - update your application!\n"); case SISFB_GET_AUTOMAXIMIZE: - if(ivideo->sisfb_max) return put_user((u32)1, argp); - else return put_user((u32)0, argp); + if(ivideo->sisfb_max) + return put_user((u32)1, argp); + else + return put_user((u32)0, argp); case SISFB_SET_AUTOMAXIMIZE_OLD: - if(ivideo->warncount++ < 50) { - printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); - } + if(ivideo->warncount++ < 10) + printk(KERN_INFO + "sisfb: Deprecated ioctl call received - update your application!\n"); case SISFB_SET_AUTOMAXIMIZE: - if(copy_from_user(&gpu32, argp, sizeof(gpu32))) { + if(get_user(gpu32, argp)) return -EFAULT; - } + ivideo->sisfb_max = (gpu32) ? 1 : 0; break; case SISFB_SET_TVPOSOFFSET: - if(copy_from_user(&gpu32, argp, sizeof(gpu32))) { + if(get_user(gpu32, argp)) return -EFAULT; - } + sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32); sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32); break; case SISFB_GET_TVPOSOFFSET: - return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)), - argp); + return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)), + argp); + + case SISFB_COMMAND: + if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg, + sizeof(struct sisfb_cmd))) + return -EFAULT; + + sisfb_handle_command(ivideo, &ivideo->sisfb_command); + + if(copy_to_user((void __user *)arg, &ivideo->sisfb_command, + sizeof(struct sisfb_cmd))) + return -EFAULT; + + break; case SISFB_SET_LOCK: - if(copy_from_user(&gpu32, argp, sizeof(gpu32))) { + if(get_user(gpu32, argp)) return -EFAULT; - } + ivideo->sisfblocked = (gpu32) ? 1 : 0; break; default: +#ifdef SIS_NEW_CONFIG_COMPAT return -ENOIOCTLCMD; +#else + return -EINVAL; +#endif } return 0; } -#ifdef CONFIG_COMPAT -static long sisfb_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg, struct fb_info *info) +#ifdef SIS_NEW_CONFIG_COMPAT +static long +sisfb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg, struct fb_info *info) { int ret; + lock_kernel(); ret = sisfb_ioctl(NULL, f, cmd, arg, info); unlock_kernel(); @@ -2219,7 +1946,7 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) strcpy(fix->id, ivideo->myid); - fix->smem_start = ivideo->video_base; + fix->smem_start = ivideo->video_base + ivideo->video_offset; fix->smem_len = ivideo->sisfb_mem; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; @@ -2231,11 +1958,17 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) fix->mmio_start = ivideo->mmio_base; fix->mmio_len = ivideo->mmio_size; if(ivideo->sisvga_engine == SIS_300_VGA) { - fix->accel = FB_ACCEL_SIS_GLAMOUR; - } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) { - fix->accel = FB_ACCEL_SIS_XABRE; + fix->accel = FB_ACCEL_SIS_GLAMOUR; + } else if((ivideo->chip == SIS_330) || + (ivideo->chip == SIS_760) || + (ivideo->chip == SIS_761)) { + fix->accel = FB_ACCEL_SIS_XABRE; + } else if(ivideo->chip == XGI_20) { + fix->accel = FB_ACCEL_XGI_VOLARI_Z; + } else if(ivideo->chip >= XGI_40) { + fix->accel = FB_ACCEL_XGI_VOLARI_V; } else { - fix->accel = FB_ACCEL_SIS_GLAMOUR_2; + fix->accel = FB_ACCEL_SIS_GLAMOUR_2; } return 0; @@ -2251,40 +1984,41 @@ static struct fb_ops sisfb_ops = { .fb_set_var = sisfb_set_var, .fb_get_cmap = sisfb_get_cmap, .fb_set_cmap = sisfb_set_cmap, - .fb_pan_display = sisfb_pan_display, + .fb_pan_display = sisfb_pan_display, .fb_ioctl = sisfb_ioctl }; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static struct fb_ops sisfb_ops = { - .owner = THIS_MODULE, - .fb_open = sisfb_open, - .fb_release = sisfb_release, - .fb_check_var = sisfb_check_var, - .fb_set_par = sisfb_set_par, - .fb_setcolreg = sisfb_setcolreg, - .fb_pan_display = sisfb_pan_display, - .fb_blank = sisfb_blank, - .fb_fillrect = fbcon_sis_fillrect, - .fb_copyarea = fbcon_sis_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, - .fb_sync = fbcon_sis_sync, - .fb_ioctl = sisfb_ioctl, -#ifdef CONFIG_COMPAT - .fb_compat_ioctl = sisfb_compat_ioctl, + .owner = THIS_MODULE, + .fb_open = sisfb_open, + .fb_release = sisfb_release, + .fb_check_var = sisfb_check_var, + .fb_set_par = sisfb_set_par, + .fb_setcolreg = sisfb_setcolreg, + .fb_pan_display = sisfb_pan_display, + .fb_blank = sisfb_blank, + .fb_fillrect = fbcon_sis_fillrect, + .fb_copyarea = fbcon_sis_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_sync = fbcon_sis_sync, +#ifdef SIS_NEW_CONFIG_COMPAT + .fb_compat_ioctl= sisfb_compat_ioctl, #endif + .fb_ioctl = sisfb_ioctl }; #endif /* ---------------- Chip generation dependent routines ---------------- */ -static struct pci_dev * sisfb_get_northbridge(int basechipid) +static struct pci_dev * __devinit +sisfb_get_northbridge(int basechipid) { struct pci_dev *pdev = NULL; int nbridgenum, nbridgeidx, i; - const unsigned short nbridgeids[] = { + static const unsigned short nbridgeids[] = { PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */ PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */ PCI_DEVICE_ID_SI_730, @@ -2292,13 +2026,14 @@ static struct pci_dev * sisfb_get_northbridge(int basechipid) PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */ PCI_DEVICE_ID_SI_651, PCI_DEVICE_ID_SI_740, - PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760 VGA */ + PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */ PCI_DEVICE_ID_SI_741, PCI_DEVICE_ID_SI_660, - PCI_DEVICE_ID_SI_760 + PCI_DEVICE_ID_SI_760, + PCI_DEVICE_ID_SI_761 }; - switch(basechipid) { + switch(basechipid) { #ifdef CONFIG_FB_SIS_300 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break; case SIS_630: nbridgeidx = 1; nbridgenum = 2; break; @@ -2306,35 +2041,40 @@ static struct pci_dev * sisfb_get_northbridge(int basechipid) #ifdef CONFIG_FB_SIS_315 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break; case SIS_650: nbridgeidx = 4; nbridgenum = 3; break; - case SIS_660: nbridgeidx = 7; nbridgenum = 4; break; + case SIS_660: nbridgeidx = 7; nbridgenum = 5; break; #endif default: return NULL; } for(i = 0; i < nbridgenum; i++) { - if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break; + if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, + nbridgeids[nbridgeidx+i], NULL))) + break; } return pdev; } -static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo) +static int __devinit +sisfb_get_dram_size(struct sis_video_info *ivideo) { #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) u8 reg; #endif ivideo->video_size = 0; + ivideo->UMAsize = ivideo->LFBsize = 0; switch(ivideo->chip) { #ifdef CONFIG_FB_SIS_300 case SIS_300: - inSISIDXREG(SISSR, 0x14, reg); + inSISIDXREG(SISSR, 0x14, reg); ivideo->video_size = ((reg & 0x3F) + 1) << 20; break; case SIS_540: case SIS_630: case SIS_730: - if(!ivideo->nbridge) return -1; - pci_read_config_byte(ivideo->nbridge, 0x63, ®); + if(!ivideo->nbridge) + return -1; + pci_read_config_byte(ivideo->nbridge, 0x63, ®); ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21); break; #endif @@ -2342,45 +2082,68 @@ static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo) case SIS_315H: case SIS_315PRO: case SIS_315: - inSISIDXREG(SISSR, 0x14, reg); + inSISIDXREG(SISSR, 0x14, reg); ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; switch((reg >> 2) & 0x03) { case 0x01: case 0x03: - ivideo->video_size <<= 1; - break; + ivideo->video_size <<= 1; + break; case 0x02: - ivideo->video_size += (ivideo->video_size/2); + ivideo->video_size += (ivideo->video_size/2); } - break; + break; case SIS_330: - inSISIDXREG(SISSR, 0x14, reg); + inSISIDXREG(SISSR, 0x14, reg); ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; if(reg & 0x0c) ivideo->video_size <<= 1; - break; + break; case SIS_550: case SIS_650: case SIS_740: - inSISIDXREG(SISSR, 0x14, reg); + inSISIDXREG(SISSR, 0x14, reg); ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20; break; case SIS_661: case SIS_741: - inSISIDXREG(SISCR, 0x79, reg); + inSISIDXREG(SISCR, 0x79, reg); ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; - break; + break; case SIS_660: case SIS_760: + case SIS_761: inSISIDXREG(SISCR, 0x79, reg); reg = (reg & 0xf0) >> 4; - if(reg) ivideo->video_size = (1 << reg) << 20; + if(reg) { + ivideo->video_size = (1 << reg) << 20; + ivideo->UMAsize = ivideo->video_size; + } inSISIDXREG(SISCR, 0x78, reg); reg &= 0x30; if(reg) { - if(reg == 0x10) ivideo->video_size += (32 << 20); - else ivideo->video_size += (64 << 20); + if(reg == 0x10) { + ivideo->LFBsize = (32 << 20); + } else { + ivideo->LFBsize = (64 << 20); + } + ivideo->video_size += ivideo->LFBsize; + } + break; + case SIS_340: + case XGI_20: + case XGI_40: + inSISIDXREG(SISSR, 0x14, reg); + ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; + if(ivideo->chip != XGI_20) { + reg = (reg & 0x0c) >> 2; + if(ivideo->revision_id == 2) { + if(reg & 0x01) reg = 0x02; + else reg = 0x00; + } + if(reg == 0x02) ivideo->video_size <<= 1; + else if(reg == 0x03) ivideo->video_size <<= 2; } - break; + break; #endif default: return -1; @@ -2390,17 +2153,24 @@ static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo) /* -------------- video bridge device detection --------------- */ -static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo) +static void __devinit +sisfb_detect_VB_connect(struct sis_video_info *ivideo) { u8 cr32, temp; + /* No CRT2 on XGI Z7 */ + if(ivideo->chip == XGI_20) { + ivideo->sisfb_crt1off = 0; + return; + } + #ifdef CONFIG_FB_SIS_300 if(ivideo->sisvga_engine == SIS_300_VGA) { inSISIDXREG(SISSR, 0x17, temp); if((temp & 0x0F) && (ivideo->chip != SIS_300)) { /* PAL/NTSC is stored on SR16 on such machines */ if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) { - inSISIDXREG(SISSR, 0x16, temp); + inSISIDXREG(SISSR, 0x16, temp); if(temp & 0x20) ivideo->vbflags |= TV_PAL; else @@ -2435,28 +2205,29 @@ static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo) if(ivideo->sisfb_tvplug != -1) { if( (ivideo->sisvga_engine != SIS_315_VGA) || - (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) { + (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) { if(ivideo->sisfb_tvplug & TV_YPBPR) { - ivideo->sisfb_tvplug = -1; + ivideo->sisfb_tvplug = -1; printk(KERN_ERR "sisfb: YPbPr not supported\n"); } } } if(ivideo->sisfb_tvplug != -1) { if( (ivideo->sisvga_engine != SIS_315_VGA) || - (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) { + (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) { if(ivideo->sisfb_tvplug & TV_HIVISION) { - ivideo->sisfb_tvplug = -1; + ivideo->sisfb_tvplug = -1; printk(KERN_ERR "sisfb: HiVision not supported\n"); } } } if(ivideo->sisfb_tvstd != -1) { - if( (!(ivideo->vbflags & VB_SISBRIDGE)) && - (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) { + if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) && + (!((ivideo->sisvga_engine == SIS_315_VGA) && + (ivideo->vbflags2 & VB2_CHRONTEL))) ) { if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) { - ivideo->sisfb_tvstd = -1; - printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n"); + ivideo->sisfb_tvstd = -1; + printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n"); } } } @@ -2468,7 +2239,7 @@ static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo) if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */ else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION; else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART; - else { + else { if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO; if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO; } @@ -2485,165 +2256,44 @@ static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo) } if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) { if(ivideo->sisvga_engine == SIS_300_VGA) { - inSISIDXREG(SISSR, 0x38, temp); + inSISIDXREG(SISSR, 0x38, temp); if(temp & 0x01) ivideo->vbflags |= TV_PAL; else ivideo->vbflags |= TV_NTSC; } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) { - inSISIDXREG(SISSR, 0x38, temp); + inSISIDXREG(SISSR, 0x38, temp); if(temp & 0x01) ivideo->vbflags |= TV_PAL; else ivideo->vbflags |= TV_NTSC; - } else { - inSISIDXREG(SISCR, 0x79, temp); + } else { + inSISIDXREG(SISCR, 0x79, temp); if(temp & 0x20) ivideo->vbflags |= TV_PAL; else ivideo->vbflags |= TV_NTSC; - } + } } } /* Copy forceCRT1 option to CRT1off if option is given */ - if(ivideo->sisfb_forcecrt1 != -1) { - ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1; - } -} - -static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo) -{ - char stdstr[] = "sisfb: Detected"; - char bridgestr[] = "video bridge"; - u8 vb_chipid; - u8 reg; - - inSISIDXREG(SISPART4, 0x00, vb_chipid); - switch(vb_chipid) { - case 0x01: - inSISIDXREG(SISPART4, 0x01, reg); - if(reg < 0xb0) { - ivideo->vbflags |= VB_301; - printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr); - } else if(reg < 0xc0) { - ivideo->vbflags |= VB_301B; - inSISIDXREG(SISPART4,0x23,reg); - if(!(reg & 0x02)) { - ivideo->vbflags |= VB_30xBDH; - printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr); - } else { - printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr); - } - } else if(reg < 0xd0) { - ivideo->vbflags |= VB_301C; - printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr); - } else if(reg < 0xe0) { - ivideo->vbflags |= VB_301LV; - printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr); - } else if(reg <= 0xe1) { - inSISIDXREG(SISPART4,0x39,reg); - if(reg == 0xff) { - ivideo->vbflags |= VB_302LV; - printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr); - } else { - ivideo->vbflags |= VB_301C; - printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr); -#if 0 - ivideo->vbflags |= VB_302ELV; - printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr); -#endif - } - } - break; - case 0x02: - ivideo->vbflags |= VB_302B; - printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr); - break; - } - - if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) { - inSISIDXREG(SISCR, 0x37, reg); - reg &= SIS_EXTERNAL_CHIP_MASK; - reg >>= 1; - if(ivideo->sisvga_engine == SIS_300_VGA) { -#ifdef CONFIG_FB_SIS_300 - switch(reg) { - case SIS_EXTERNAL_CHIP_LVDS: - ivideo->vbflags |= VB_LVDS; - break; - case SIS_EXTERNAL_CHIP_TRUMPION: - ivideo->vbflags |= VB_TRUMPION; - break; - case SIS_EXTERNAL_CHIP_CHRONTEL: - ivideo->vbflags |= VB_CHRONTEL; - break; - case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL: - ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); - break; - } - if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1; -#endif - } else if(ivideo->chip < SIS_661) { -#ifdef CONFIG_FB_SIS_315 - switch (reg) { - case SIS310_EXTERNAL_CHIP_LVDS: - ivideo->vbflags |= VB_LVDS; - break; - case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL: - ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); - break; - } - if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2; -#endif - } else if(ivideo->chip >= SIS_661) { -#ifdef CONFIG_FB_SIS_315 - inSISIDXREG(SISCR, 0x38, reg); - reg >>= 5; - switch(reg) { - case 0x02: - ivideo->vbflags |= VB_LVDS; - break; - case 0x03: - ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); - break; - case 0x04: - ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); - break; - } - if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2; -#endif - } - if(ivideo->vbflags & VB_LVDS) { - printk(KERN_INFO "%s LVDS transmitter\n", stdstr); - } - if(ivideo->vbflags & VB_TRUMPION) { - printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr); - } - if(ivideo->vbflags & VB_CHRONTEL) { - printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr); - } - if(ivideo->vbflags & VB_CONEXANT) { - printk(KERN_INFO "%s Conexant external device\n", stdstr); - } - } - - if(ivideo->vbflags & VB_SISBRIDGE) { - SiS_Sense30x(ivideo); - } else if(ivideo->vbflags & VB_CHRONTEL) { - SiS_SenseCh(ivideo); + if(ivideo->sisfb_forcecrt1 != -1) { + ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1; } } /* ------------------ Sensing routines ------------------ */ -static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo) +static BOOLEAN __devinit +sisfb_test_DDC1(struct sis_video_info *ivideo) { unsigned short old; int count = 48; old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr); do { - if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break; + if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break; } while(count--); return (count == -1) ? FALSE : TRUE; } -static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo) +static void __devinit +sisfb_sense_crt1(struct sis_video_info *ivideo) { BOOLEAN mustwait = FALSE; u8 sr1F, cr17; @@ -2699,7 +2349,8 @@ static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo) if(temp == 0xffff) { i = 3; do { - temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL); + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, + ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2); } while(((temp == 0) || (temp == 0xffff)) && i--); if((temp == 0) || (temp == 0xffff)) { @@ -2723,7 +2374,96 @@ static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo) } /* Determine and detect attached devices on SiS30x */ -static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test) +static void __devinit +SiS_SenseLCD(struct sis_video_info *ivideo) +{ + unsigned char buffer[256]; + unsigned short temp, realcrtno, i; + u8 reg, cr37 = 0, paneltype = 0; + u16 xres, yres; + + ivideo->SiS_Pr.PanelSelfDetected = FALSE; + + /* LCD detection only for TMDS bridges */ + if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE)) + return; + if(ivideo->vbflags2 & VB2_30xBDH) + return; + + /* If LCD already set up by BIOS, skip it */ + inSISIDXREG(SISCR, 0x32, reg); + if(reg & 0x08) + return; + + realcrtno = 1; + if(ivideo->SiS_Pr.DDCPortMixup) + realcrtno = 0; + + /* Check DDC capabilities */ + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, + realcrtno, 0, &buffer[0], ivideo->vbflags2); + + if((!temp) || (temp == 0xffff) || (!(temp & 0x02))) + return; + + /* Read DDC data */ + i = 3; /* Number of retrys */ + do { + temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, + ivideo->sisvga_engine, realcrtno, 1, + &buffer[0], ivideo->vbflags2); + } while((temp) && i--); + + if(temp) + return; + + /* No digital device */ + if(!(buffer[0x14] & 0x80)) + return; + + /* First detailed timing preferred timing? */ + if(!(buffer[0x18] & 0x02)) + return; + + xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4); + yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4); + + switch(xres) { + case 1024: + if(yres == 768) + paneltype = 0x02; + break; + case 1280: + if(yres == 1024) + paneltype = 0x03; + break; + case 1600: + if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC)) + paneltype = 0x0b; + break; + } + + if(!paneltype) + return; + + if(buffer[0x23]) + cr37 |= 0x10; + + if((buffer[0x47] & 0x18) == 0x18) + cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20); + else + cr37 |= 0xc0; + + outSISIDXREG(SISCR, 0x36, paneltype); + cr37 &= 0xf1; + setSISIDXREG(SISCR, 0x37, 0x0c, cr37); + orSISIDXREG(SISCR, 0x32, 0x08); + + ivideo->SiS_Pr.PanelSelfDetected = TRUE; +} + +static int __devinit +SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test) { int temp, mytest, result, i, j; @@ -2749,10 +2489,11 @@ static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 tes } if((result == 0) || (result >= 2)) break; } - return(result); + return result; } -static void __devinit SiS_Sense30x(struct sis_video_info *ivideo) +static void __devinit +SiS_Sense30x(struct sis_video_info *ivideo) { u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0; u16 svhs=0, svhs_c=0; @@ -2762,36 +2503,51 @@ static void __devinit SiS_Sense30x(struct sis_video_info *ivideo) char stdstr[] = "sisfb: Detected"; char tvstr[] = "TV connected to"; - if(ivideo->vbflags & VB_301) { + if(ivideo->vbflags2 & VB2_301) { svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1; inSISIDXREG(SISPART4,0x01,myflag); if(myflag & 0x04) { svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd; } - } else if(ivideo->vbflags & (VB_301B | VB_302B)) { + } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) { svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190; - } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) { + } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) { svhs = 0x0200; cvbs = 0x0100; - } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) { + } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) { svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190; - } else return; + } else + return; vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804; - if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) { + if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) { svhs_c = 0x0408; cvbs_c = 0x0808; } + biosflag = 2; + if(ivideo->haveXGIROM) { + biosflag = ivideo->bios_abase[0x58] & 0x03; + } else if(ivideo->newrom) { + if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01; + } else if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->bios_abase) { + biosflag = ivideo->bios_abase[0xfe] & 0x03; + } + } if(ivideo->chip == SIS_300) { inSISIDXREG(SISSR,0x3b,myflag); if(!(myflag & 0x01)) vga2 = vga2_c = 0; } + if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) { + vga2 = vga2_c = 0; + } + inSISIDXREG(SISSR,0x1e,backupSR_1e); orSISIDXREG(SISSR,0x1e,0x20); inSISIDXREG(SISPART4,0x0d,backupP4_0d); - if(ivideo->vbflags & VB_301C) { + if(ivideo->vbflags2 & VB2_30xC) { setSISIDXREG(SISPART4,0x0d,~0x07,0x01); } else { orSISIDXREG(SISPART4,0x0d,0x04); @@ -2802,11 +2558,11 @@ static void __devinit SiS_Sense30x(struct sis_video_info *ivideo) outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc)); inSISIDXREG(SISPART2,0x4d,backupP2_4d); - if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) { + if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) { outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10)); } - if(!(ivideo->vbflags & VB_301C)) { + if(!(ivideo->vbflags2 & VB2_30xCLV)) { SISDoSense(ivideo, 0, 0); } @@ -2826,12 +2582,11 @@ static void __devinit SiS_Sense30x(struct sis_video_info *ivideo) andSISIDXREG(SISCR, 0x32, 0x3f); - if(ivideo->vbflags & VB_301C) { + if(ivideo->vbflags2 & VB2_30xCLV) { orSISIDXREG(SISPART4,0x0d,0x04); } - if((ivideo->sisvga_engine == SIS_315_VGA) && - (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) { + if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) { outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10)); SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000); if((result = SISDoSense(ivideo, svhs, 0x0604))) { @@ -2864,7 +2619,7 @@ static void __devinit SiS_Sense30x(struct sis_video_info *ivideo) outSISIDXREG(SISPART4,0x0d,backupP4_0d); outSISIDXREG(SISSR,0x1e,backupSR_1e); - if(ivideo->vbflags & VB_301C) { + if(ivideo->vbflags2 & VB2_30xCLV) { inSISIDXREG(SISPART2,0x00,biosflag); if(biosflag & 0x20) { for(myflag = 2; myflag > 0; myflag--) { @@ -2878,7 +2633,8 @@ static void __devinit SiS_Sense30x(struct sis_video_info *ivideo) } /* Determine and detect attached TV's on Chrontel */ -static void __devinit SiS_SenseCh(struct sis_video_info *ivideo) +static void __devinit +SiS_SenseCh(struct sis_video_info *ivideo) { #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) u8 temp1, temp2; @@ -2899,7 +2655,7 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo) /* See Chrontel TB31 for explanation */ temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e); if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) { - SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e); + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b); SiS_DDC2Delay(&ivideo->SiS_Pr, 300); } temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25); @@ -2909,15 +2665,15 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo) /* Read power status */ temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e); if((temp1 & 0x03) != 0x03) { - /* Power all outputs */ - SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E); + /* Power all outputs */ + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b); SiS_DDC2Delay(&ivideo->SiS_Pr, 300); } /* Sense connected TV devices */ for(i = 0; i < 3; i++) { - SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110); + SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01); SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); - SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010); + SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00); SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10); if(!(temp1 & 0x08)) test[i] = 0x02; @@ -2930,7 +2686,7 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo) else if(test[0] == test[2]) temp1 = test[0]; else if(test[1] == test[2]) temp1 = test[1]; else { - printk(KERN_INFO + printk(KERN_INFO "sisfb: TV detection unreliable - test results varied\n"); temp1 = test[2]; } @@ -2945,11 +2701,11 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo) orSISIDXREG(SISCR, 0x32, 0x01); andSISIDXREG(SISCR, 0x32, ~0x06); } else { - SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8); + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8); andSISIDXREG(SISCR, 0x32, ~0x07); } } else if(temp1 == 0) { - SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8); + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8); andSISIDXREG(SISCR, 0x32, ~0x07); } /* Set general purpose IO for Chrontel communication */ @@ -2960,19 +2716,19 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo) #ifdef CONFIG_FB_SIS_315 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */ - temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49); - SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049); + temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49); + SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20); SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20); temp2 |= 0x01; - SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20); + SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2); SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); temp2 ^= 0x01; - SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20); + SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2); SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96); temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20); - SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49); - temp1 = 0; + SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1); + temp1 = 0; if(temp2 & 0x02) temp1 |= 0x01; if(temp2 & 0x10) temp1 |= 0x01; if(temp2 & 0x04) temp1 |= 0x02; @@ -2983,18 +2739,18 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo) ivideo->vbflags |= TV_AVIDEO; orSISIDXREG(SISCR, 0x32, 0x01); andSISIDXREG(SISCR, 0x32, ~0x06); - break; + break; case 0x02: printk(KERN_INFO "%s SVIDEO output\n", stdstr); ivideo->vbflags |= TV_SVIDEO; orSISIDXREG(SISCR, 0x32, 0x02); andSISIDXREG(SISCR, 0x32, ~0x05); - break; + break; case 0x04: printk(KERN_INFO "%s SCART output\n", stdstr); orSISIDXREG(SISCR, 0x32, 0x04); andSISIDXREG(SISCR, 0x32, ~0x03); - break; + break; default: andSISIDXREG(SISCR, 0x32, ~0x07); } @@ -3002,165 +2758,589 @@ static void __devinit SiS_SenseCh(struct sis_video_info *ivideo) } } -/* ------------------------ Heap routines -------------------------- */ - -static u32 __devinit -sisfb_getheapstart(struct sis_video_info *ivideo) +static void __devinit +sisfb_get_VB_type(struct sis_video_info *ivideo) { - u32 ret = ivideo->sisfb_parm_mem * 1024; - u32 max = ivideo->video_size - ivideo->hwcursor_size; - u32 def; + char stdstr[] = "sisfb: Detected"; + char bridgestr[] = "video bridge"; + u8 vb_chipid; + u8 reg; - /* Calculate heap start = end of memory for console - * - * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ - * C = console, D = heap, H = HWCursor, Q = cmd-queue - * - * Basically given by "mem" parameter - * - * maximum = videosize - cmd_queue - hwcursor - * (results in a heap of size 0) - * default = SiS 300: depends on videosize - * SiS 315/330: 32k below max - */ + /* No CRT2 on XGI Z7 */ + if(ivideo->chip == XGI_20) + return; - if(ivideo->sisvga_engine == SIS_300_VGA) { - max -= TURBO_QUEUE_AREA_SIZE; - if(ivideo->video_size > 0x1000000) { - def = 0xc00000; - } else if(ivideo->video_size > 0x800000) { - def = 0x800000; - } else { - def = 0x400000; - } - } else { - max -= COMMAND_QUEUE_AREA_SIZE; - def = max - 0x8000; + inSISIDXREG(SISPART4, 0x00, vb_chipid); + switch(vb_chipid) { + case 0x01: + inSISIDXREG(SISPART4, 0x01, reg); + if(reg < 0xb0) { + ivideo->vbflags |= VB_301; /* Deprecated */ + ivideo->vbflags2 |= VB2_301; + printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr); + } else if(reg < 0xc0) { + ivideo->vbflags |= VB_301B; /* Deprecated */ + ivideo->vbflags2 |= VB2_301B; + inSISIDXREG(SISPART4,0x23,reg); + if(!(reg & 0x02)) { + ivideo->vbflags |= VB_30xBDH; /* Deprecated */ + ivideo->vbflags2 |= VB2_30xBDH; + printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr); + } else { + printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr); + } + } else if(reg < 0xd0) { + ivideo->vbflags |= VB_301C; /* Deprecated */ + ivideo->vbflags2 |= VB2_301C; + printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr); + } else if(reg < 0xe0) { + ivideo->vbflags |= VB_301LV; /* Deprecated */ + ivideo->vbflags2 |= VB2_301LV; + printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr); + } else if(reg <= 0xe1) { + inSISIDXREG(SISPART4,0x39,reg); + if(reg == 0xff) { + ivideo->vbflags |= VB_302LV; /* Deprecated */ + ivideo->vbflags2 |= VB2_302LV; + printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr); + } else { + ivideo->vbflags |= VB_301C; /* Deprecated */ + ivideo->vbflags2 |= VB2_301C; + printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr); +#if 0 + ivideo->vbflags |= VB_302ELV; /* Deprecated */ + ivideo->vbflags2 |= VB2_302ELV; + printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr); +#endif + } + } + break; + case 0x02: + ivideo->vbflags |= VB_302B; /* Deprecated */ + ivideo->vbflags2 |= VB2_302B; + printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr); + break; } - if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) { - ret = def; - } - - return ret; -} - -static int __devinit -sisfb_heap_init(struct sis_video_info *ivideo) + if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) { + inSISIDXREG(SISCR, 0x37, reg); + reg &= SIS_EXTERNAL_CHIP_MASK; + reg >>= 1; + if(ivideo->sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 + switch(reg) { + case SIS_EXTERNAL_CHIP_LVDS: + ivideo->vbflags |= VB_LVDS; /* Deprecated */ + ivideo->vbflags2 |= VB2_LVDS; + break; + case SIS_EXTERNAL_CHIP_TRUMPION: + ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */ + ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION); + break; + case SIS_EXTERNAL_CHIP_CHRONTEL: + ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */ + ivideo->vbflags2 |= VB2_CHRONTEL; + break; + case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL: + ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */ + ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL); + break; + } + if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1; +#endif + } else if(ivideo->chip < SIS_661) { +#ifdef CONFIG_FB_SIS_315 + switch (reg) { + case SIS310_EXTERNAL_CHIP_LVDS: + ivideo->vbflags |= VB_LVDS; /* Deprecated */ + ivideo->vbflags2 |= VB2_LVDS; + break; + case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL: + ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */ + ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL); + break; + } + if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2; +#endif + } else if(ivideo->chip >= SIS_661) { +#ifdef CONFIG_FB_SIS_315 + inSISIDXREG(SISCR, 0x38, reg); + reg >>= 5; + switch(reg) { + case 0x02: + ivideo->vbflags |= VB_LVDS; /* Deprecated */ + ivideo->vbflags2 |= VB2_LVDS; + break; + case 0x03: + ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */ + ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL); + break; + case 0x04: + ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */ + ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT); + break; + } + if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2; +#endif + } + if(ivideo->vbflags2 & VB2_LVDS) { + printk(KERN_INFO "%s LVDS transmitter\n", stdstr); + } + if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) { + printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr); + } + if(ivideo->vbflags2 & VB2_CHRONTEL) { + printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr); + } + if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) { + printk(KERN_INFO "%s Conexant external device\n", stdstr); + } + } + + if(ivideo->vbflags2 & VB2_SISBRIDGE) { + SiS_SenseLCD(ivideo); + SiS_Sense30x(ivideo); + } else if(ivideo->vbflags2 & VB2_CHRONTEL) { + SiS_SenseCh(ivideo); + } +} + +/* ---------- Engine initialization routines ------------ */ + +static void +sisfb_engine_init(struct sis_video_info *ivideo) { - SIS_OH *poh; - ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo); + /* Initialize command queue (we use MMIO only) */ - ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart; - ivideo->sisfb_heap_end = ivideo->video_vbase + ivideo->video_size; + /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */ - /* Initialize command queue (We use MMIO only) */ + ivideo->caps &= ~(TURBO_QUEUE_CAP | + MMIO_CMD_QUEUE_CAP | + VM_CMD_QUEUE_CAP | + AGP_CMD_QUEUE_CAP); + +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + u32 tqueue_pos; + u8 tq_state; + + tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024); + + inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state); + tq_state |= 0xf0; + tq_state &= 0xfc; + tq_state |= (u8)(tqueue_pos >> 8); + outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state); + + outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff)); + + ivideo->caps |= TURBO_QUEUE_CAP; + } +#endif #ifdef CONFIG_FB_SIS_315 - if(ivideo->sisvga_engine == SIS_315_VGA) { - u32 tempq = 0; - u8 temp = 0; + if(ivideo->sisvga_engine == SIS_315_VGA) { + u32 tempq = 0, templ; + u8 temp; + + if(ivideo->chip == XGI_20) { + switch(ivideo->cmdQueueSize) { + case (64 * 1024): + temp = SIS_CMD_QUEUE_SIZE_Z7_64k; + break; + case (128 * 1024): + default: + temp = SIS_CMD_QUEUE_SIZE_Z7_128k; + } + } else { + switch(ivideo->cmdQueueSize) { + case (4 * 1024 * 1024): + temp = SIS_CMD_QUEUE_SIZE_4M; + break; + case (2 * 1024 * 1024): + temp = SIS_CMD_QUEUE_SIZE_2M; + break; + case (1 * 1024 * 1024): + temp = SIS_CMD_QUEUE_SIZE_1M; + break; + default: + case (512 * 1024): + temp = SIS_CMD_QUEUE_SIZE_512k; + } + } + + outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD); + outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET); + + if((ivideo->chip >= XGI_40) && ivideo->modechanged) { + /* Must disable dual pipe on XGI_40. Can't do + * this in MMIO mode, because it requires + * setting/clearing a bit in the MMIO fire trigger + * register. + */ + if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) { + + MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0); + + outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE)); + + tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR); + MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq); - ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE; + tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize); + MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq); - outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD); - outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET); + writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq); + writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4); + writel(0x168F0000, ivideo->video_vbase + tempq + 8); + writel(0x168F0000, ivideo->video_vbase + tempq + 12); + + MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16)); + + sisfb_syncaccel(ivideo); + + outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET); + + } + } + + tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT); + MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq); + + temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR); + outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp); + + tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize); + MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq); + + ivideo->caps |= MMIO_CMD_QUEUE_CAP; + } +#endif + + ivideo->engineok = 1; +} + +static void __devinit +sisfb_detect_lcd_type(struct sis_video_info *ivideo) +{ + u8 reg; + int i; - tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT); - MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq); + inSISIDXREG(SISCR, 0x36, reg); + reg &= 0x0f; + if(ivideo->sisvga_engine == SIS_300_VGA) { + ivideo->CRT2LCDType = sis300paneltype[reg]; + } else if(ivideo->chip >= SIS_661) { + ivideo->CRT2LCDType = sis661paneltype[reg]; + } else { + ivideo->CRT2LCDType = sis310paneltype[reg]; + if((ivideo->chip == SIS_550) && (sisfb_fstn)) { + if((ivideo->CRT2LCDType != LCD_320x240_2) && + (ivideo->CRT2LCDType != LCD_320x240_3)) { + ivideo->CRT2LCDType = LCD_320x240; + } + } + } - temp = SIS_CMD_QUEUE_SIZE_512k; - temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR); - outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp); + if(ivideo->CRT2LCDType == LCD_UNKNOWN) { + /* For broken BIOSes: Assume 1024x768, RGB18 */ + ivideo->CRT2LCDType = LCD_1024x768; + setSISIDXREG(SISCR,0x36,0xf0,0x02); + setSISIDXREG(SISCR,0x37,0xee,0x01); + printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg); + } - tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE); - MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq); + for(i = 0; i < SIS_LCD_NUMBER; i++) { + if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) { + ivideo->lcdxres = sis_lcd_data[i].xres; + ivideo->lcdyres = sis_lcd_data[i].yres; + ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx; + break; + } + } - ivideo->caps |= MMIO_CMD_QUEUE_CAP; - } +#ifdef CONFIG_FB_SIS_300 + if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) { + ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; + ivideo->lcddefmodeidx = DEFAULT_MODE_1360; + } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) { + ivideo->lcdxres = 848; ivideo->lcdyres = 480; + ivideo->lcddefmodeidx = DEFAULT_MODE_848; + } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) { + ivideo->lcdxres = 856; ivideo->lcdyres = 480; + ivideo->lcddefmodeidx = DEFAULT_MODE_856; + } #endif + printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n", + ivideo->lcdxres, ivideo->lcdyres); +} + +static void __devinit +sisfb_save_pdc_emi(struct sis_video_info *ivideo) +{ #ifdef CONFIG_FB_SIS_300 - if(ivideo->sisvga_engine == SIS_300_VGA) { - unsigned long tqueue_pos; - u8 tq_state; + /* Save the current PanelDelayCompensation if the LCD is currently used */ + if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) { + int tmp; + inSISIDXREG(SISCR,0x30,tmp); + if(tmp & 0x20) { + /* Currently on LCD? If yes, read current pdc */ + inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc); + ivideo->detectedpdc &= 0x3c; + if(ivideo->SiS_Pr.PDC == -1) { + /* Let option override detection */ + ivideo->SiS_Pr.PDC = ivideo->detectedpdc; + } + printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n", + ivideo->detectedpdc); + } + if((ivideo->SiS_Pr.PDC != -1) && + (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) { + printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n", + ivideo->SiS_Pr.PDC); + } + } + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { - ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE; + /* Try to find about LCDA */ + if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) { + int tmp; + inSISIDXREG(SISPART1,0x13,tmp); + if(tmp & 0x04) { + ivideo->SiS_Pr.SiS_UseLCDA = TRUE; + ivideo->detectedlcda = 0x03; + } + } - tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024); + /* Save PDC */ + if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) { + int tmp; + inSISIDXREG(SISCR,0x30,tmp); + if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) { + /* Currently on LCD? If yes, read current pdc */ + u8 pdc; + inSISIDXREG(SISPART1,0x2D,pdc); + ivideo->detectedpdc = (pdc & 0x0f) << 1; + ivideo->detectedpdca = (pdc & 0xf0) >> 3; + inSISIDXREG(SISPART1,0x35,pdc); + ivideo->detectedpdc |= ((pdc >> 7) & 0x01); + inSISIDXREG(SISPART1,0x20,pdc); + ivideo->detectedpdca |= ((pdc >> 6) & 0x01); + if(ivideo->newrom) { + /* New ROM invalidates other PDC resp. */ + if(ivideo->detectedlcda != 0xff) { + ivideo->detectedpdc = 0xff; + } else { + ivideo->detectedpdca = 0xff; + } + } + if(ivideo->SiS_Pr.PDC == -1) { + if(ivideo->detectedpdc != 0xff) { + ivideo->SiS_Pr.PDC = ivideo->detectedpdc; + } + } + if(ivideo->SiS_Pr.PDCA == -1) { + if(ivideo->detectedpdca != 0xff) { + ivideo->SiS_Pr.PDCA = ivideo->detectedpdca; + } + } + if(ivideo->detectedpdc != 0xff) { + printk(KERN_INFO + "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n", + ivideo->detectedpdc); + } + if(ivideo->detectedpdca != 0xff) { + printk(KERN_INFO + "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n", + ivideo->detectedpdca); + } + } - inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state); - tq_state |= 0xf0; - tq_state &= 0xfc; - tq_state |= (u8)(tqueue_pos >> 8); - outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state); + /* Save EMI */ + if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) { + inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30); + inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31); + inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32); + inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33); + ivideo->SiS_Pr.HaveEMI = TRUE; + if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) { + ivideo->SiS_Pr.HaveEMILCD = TRUE; + } + } + } - outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff)); + /* Let user override detected PDCs (all bridges) */ + if(ivideo->vbflags2 & VB2_30xBLV) { + if((ivideo->SiS_Pr.PDC != -1) && + (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) { + printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n", + ivideo->SiS_Pr.PDC); + } + if((ivideo->SiS_Pr.PDCA != -1) && + (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) { + printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n", + ivideo->SiS_Pr.PDCA); + } + } - ivideo->caps |= TURBO_QUEUE_CAP; - } + } #endif +} + +/* -------------------- Memory manager routines ---------------------- */ + +static u32 __devinit +sisfb_getheapstart(struct sis_video_info *ivideo) +{ + u32 ret = ivideo->sisfb_parm_mem * 1024; + u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize; + u32 def; + + /* Calculate heap start = end of memory for console + * + * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ + * C = console, D = heap, H = HWCursor, Q = cmd-queue + * + * On 76x in UMA+LFB mode, the layout is as follows: + * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ + * where the heap is the entire UMA area, eventually + * into the LFB area if the given mem parameter is + * higher than the size of the UMA memory. + * + * Basically given by "mem" parameter + * + * maximum = videosize - cmd_queue - hwcursor + * (results in a heap of size 0) + * default = SiS 300: depends on videosize + * SiS 315/330/340/XGI: 32k below max + */ + + if(ivideo->sisvga_engine == SIS_300_VGA) { + if(ivideo->video_size > 0x1000000) { + def = 0xc00000; + } else if(ivideo->video_size > 0x800000) { + def = 0x800000; + } else { + def = 0x400000; + } + } else if(ivideo->UMAsize && ivideo->LFBsize) { + ret = def = 0; + } else { + def = maxoffs - 0x8000; + } + + /* Use default for secondary card for now (FIXME) */ + if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0)) + ret = def; + + return ret; +} + +static u32 __devinit +sisfb_getheapsize(struct sis_video_info *ivideo) +{ + u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize; + u32 ret = 0; + + if(ivideo->UMAsize && ivideo->LFBsize) { + if( (!ivideo->sisfb_parm_mem) || + ((ivideo->sisfb_parm_mem * 1024) > max) || + ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) { + ret = ivideo->UMAsize; + max -= ivideo->UMAsize; + } else { + ret = max - (ivideo->sisfb_parm_mem * 1024); + max = ivideo->sisfb_parm_mem * 1024; + } + ivideo->video_offset = ret; + ivideo->sisfb_mem = max; + } else { + ret = max - ivideo->heapstart; + ivideo->sisfb_mem = ivideo->heapstart; + } - /* Reserve memory for the HWCursor */ - ivideo->sisfb_heap_end -= ivideo->hwcursor_size; - ivideo->hwcursor_vbase = ivideo->sisfb_heap_end; - ivideo->caps |= HW_CURSOR_CAP; + return ret; +} - ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start; +static int __devinit +sisfb_heap_init(struct sis_video_info *ivideo) +{ + struct SIS_OH *poh; - if(ivideo->cardnumber == 0) { + ivideo->video_offset = 0; + if(ivideo->sisfb_parm_mem) { + if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) || + (ivideo->sisfb_parm_mem > ivideo->video_size) ) { + ivideo->sisfb_parm_mem = 0; + } + } - printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n", - (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024)); + ivideo->heapstart = sisfb_getheapstart(ivideo); + ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo); - sisfb_heap.vinfo = ivideo; + ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart; + ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size; - sisfb_heap.poha_chain = NULL; - sisfb_heap.poh_freelist = NULL; + printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n", + (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024)); - poh = sisfb_poh_new_node(); - if(poh == NULL) return 1; + ivideo->sisfb_heap.vinfo = ivideo; - poh->poh_next = &sisfb_heap.oh_free; - poh->poh_prev = &sisfb_heap.oh_free; - poh->size = ivideo->sisfb_heap_size; - poh->offset = ivideo->heapstart; + ivideo->sisfb_heap.poha_chain = NULL; + ivideo->sisfb_heap.poh_freelist = NULL; - sisfb_heap.oh_free.poh_next = poh; - sisfb_heap.oh_free.poh_prev = poh; - sisfb_heap.oh_free.size = 0; - sisfb_heap.max_freesize = poh->size; + poh = sisfb_poh_new_node(&ivideo->sisfb_heap); + if(poh == NULL) + return 1; - sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used; - sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used; - sisfb_heap.oh_used.size = SENTINEL; + poh->poh_next = &ivideo->sisfb_heap.oh_free; + poh->poh_prev = &ivideo->sisfb_heap.oh_free; + poh->size = ivideo->sisfb_heap_size; + poh->offset = ivideo->heapstart; - } else { + ivideo->sisfb_heap.oh_free.poh_next = poh; + ivideo->sisfb_heap.oh_free.poh_prev = poh; + ivideo->sisfb_heap.oh_free.size = 0; + ivideo->sisfb_heap.max_freesize = poh->size; - printk(KERN_INFO "Skipped heap initialization for secondary cards\n"); + ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used; + ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used; + ivideo->sisfb_heap.oh_used.size = SENTINEL; - } + if(ivideo->cardnumber == 0) { + /* For the first card, make this heap the "global" one + * for old DRM (which could handle only one card) + */ + sisfb_heap = &ivideo->sisfb_heap; + } - return 0; + return 0; } -static SIS_OH * -sisfb_poh_new_node(void) +static struct SIS_OH * +sisfb_poh_new_node(struct SIS_HEAP *memheap) { - int i; - unsigned long cOhs; - SIS_OHALLOC *poha; - SIS_OH *poh; + struct SIS_OHALLOC *poha; + struct SIS_OH *poh; + unsigned long cOhs; + int i; - if(sisfb_heap.poh_freelist == NULL) { + if(memheap->poh_freelist == NULL) { poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL); - if(!poha) return NULL; + if(!poha) + return NULL; - poha->poha_next = sisfb_heap.poha_chain; - sisfb_heap.poha_chain = poha; + poha->poha_next = memheap->poha_chain; + memheap->poha_chain = poha; - cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1; + cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1; poh = &poha->aoh[0]; for(i = cOhs - 1; i != 0; i--) { @@ -3169,32 +3349,32 @@ sisfb_poh_new_node(void) } poh->poh_next = NULL; - sisfb_heap.poh_freelist = &poha->aoh[0]; + memheap->poh_freelist = &poha->aoh[0]; } - poh = sisfb_heap.poh_freelist; - sisfb_heap.poh_freelist = poh->poh_next; + poh = memheap->poh_freelist; + memheap->poh_freelist = poh->poh_next; - return (poh); + return poh; } -static SIS_OH * -sisfb_poh_allocate(u32 size) +static struct SIS_OH * +sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size) { - SIS_OH *pohThis; - SIS_OH *pohRoot; - int bAllocated = 0; + struct SIS_OH *pohThis; + struct SIS_OH *pohRoot; + int bAllocated = 0; - if(size > sisfb_heap.max_freesize) { + if(size > memheap->max_freesize) { DPRINTK("sisfb: Can't allocate %dk video memory\n", (unsigned int) size / 1024); - return (NULL); + return NULL; } - pohThis = sisfb_heap.oh_free.poh_next; + pohThis = memheap->oh_free.poh_next; - while(pohThis != &sisfb_heap.oh_free) { - if (size <= pohThis->size) { + while(pohThis != &memheap->oh_free) { + if(size <= pohThis->size) { bAllocated = 1; break; } @@ -3204,18 +3384,16 @@ sisfb_poh_allocate(u32 size) if(!bAllocated) { DPRINTK("sisfb: Can't allocate %dk video memory\n", (unsigned int) size / 1024); - return (NULL); + return NULL; } if(size == pohThis->size) { pohRoot = pohThis; sisfb_delete_node(pohThis); } else { - pohRoot = sisfb_poh_new_node(); - - if(pohRoot == NULL) { - return (NULL); - } + pohRoot = sisfb_poh_new_node(memheap); + if(pohRoot == NULL) + return NULL; pohRoot->offset = pohThis->offset; pohRoot->size = size; @@ -3224,33 +3402,25 @@ sisfb_poh_allocate(u32 size) pohThis->size -= size; } - sisfb_heap.max_freesize -= size; + memheap->max_freesize -= size; - pohThis = &sisfb_heap.oh_used; + pohThis = &memheap->oh_used; sisfb_insert_node(pohThis, pohRoot); - return (pohRoot); + return pohRoot; } static void -sisfb_delete_node(SIS_OH *poh) +sisfb_delete_node(struct SIS_OH *poh) { - SIS_OH *poh_prev; - SIS_OH *poh_next; - - poh_prev = poh->poh_prev; - poh_next = poh->poh_next; - - poh_prev->poh_next = poh_next; - poh_next->poh_prev = poh_prev; + poh->poh_prev->poh_next = poh->poh_next; + poh->poh_next->poh_prev = poh->poh_prev; } static void -sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh) +sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh) { - SIS_OH *pohTemp; - - pohTemp = pohList->poh_next; + struct SIS_OH *pohTemp = pohList->poh_next; pohList->poh_next = poh; pohTemp->poh_prev = poh; @@ -3259,20 +3429,20 @@ sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh) poh->poh_next = pohTemp; } -static SIS_OH * -sisfb_poh_free(u32 base) +static struct SIS_OH * +sisfb_poh_free(struct SIS_HEAP *memheap, u32 base) { - SIS_OH *pohThis; - SIS_OH *poh_freed; - SIS_OH *poh_prev; - SIS_OH *poh_next; - u32 ulUpper; - u32 ulLower; - int foundNode = 0; + struct SIS_OH *pohThis; + struct SIS_OH *poh_freed; + struct SIS_OH *poh_prev; + struct SIS_OH *poh_next; + u32 ulUpper; + u32 ulLower; + int foundNode = 0; - poh_freed = sisfb_heap.oh_used.poh_next; + poh_freed = memheap->oh_used.poh_next; - while(poh_freed != &sisfb_heap.oh_used) { + while(poh_freed != &memheap->oh_used) { if(poh_freed->offset == base) { foundNode = 1; break; @@ -3281,17 +3451,18 @@ sisfb_poh_free(u32 base) poh_freed = poh_freed->poh_next; } - if(!foundNode) return(NULL); + if(!foundNode) + return NULL; - sisfb_heap.max_freesize += poh_freed->size; + memheap->max_freesize += poh_freed->size; poh_prev = poh_next = NULL; ulUpper = poh_freed->offset + poh_freed->size; ulLower = poh_freed->offset; - pohThis = sisfb_heap.oh_free.poh_next; + pohThis = memheap->oh_free.poh_next; - while(pohThis != &sisfb_heap.oh_free) { + while(pohThis != &memheap->oh_free) { if(pohThis->offset == ulUpper) { poh_next = pohThis; } else if((pohThis->offset + pohThis->size) == ulLower) { @@ -3305,70 +3476,88 @@ sisfb_poh_free(u32 base) if(poh_prev && poh_next) { poh_prev->size += (poh_freed->size + poh_next->size); sisfb_delete_node(poh_next); - sisfb_free_node(poh_freed); - sisfb_free_node(poh_next); - return(poh_prev); + sisfb_free_node(memheap, poh_freed); + sisfb_free_node(memheap, poh_next); + return poh_prev; } if(poh_prev) { poh_prev->size += poh_freed->size; - sisfb_free_node(poh_freed); - return(poh_prev); + sisfb_free_node(memheap, poh_freed); + return poh_prev; } if(poh_next) { poh_next->size += poh_freed->size; poh_next->offset = poh_freed->offset; - sisfb_free_node(poh_freed); - return(poh_next); + sisfb_free_node(memheap, poh_freed); + return poh_next; } - sisfb_insert_node(&sisfb_heap.oh_free, poh_freed); + sisfb_insert_node(&memheap->oh_free, poh_freed); - return(poh_freed); + return poh_freed; } static void -sisfb_free_node(SIS_OH *poh) +sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh) { - if(poh == NULL) return; + if(poh == NULL) + return; - poh->poh_next = sisfb_heap.poh_freelist; - sisfb_heap.poh_freelist = poh; + poh->poh_next = memheap->poh_freelist; + memheap->poh_freelist = poh; } -void -sis_malloc(struct sis_memreq *req) +static void +sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req) { - struct sis_video_info *ivideo = sisfb_heap.vinfo; - SIS_OH *poh = NULL; + struct SIS_OH *poh = NULL; - if((ivideo) && (!ivideo->havenoheap)) { - poh = sisfb_poh_allocate((u32)req->size); - } + if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap)) + poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size); if(poh == NULL) { - req->offset = req->size = 0; - DPRINTK("sisfb: Video RAM allocation failed\n"); + req->offset = req->size = 0; + DPRINTK("sisfb: Video RAM allocation failed\n"); } else { - req->offset = poh->offset; - req->size = poh->size; - DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n", - (poh->offset + ivideo->video_vbase)); + req->offset = poh->offset; + req->size = poh->size; + DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n", + (poh->offset + ivideo->video_vbase)); } } -/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */ +void +sis_malloc(struct sis_memreq *req) +{ + struct sis_video_info *ivideo = sisfb_heap->vinfo; + + if(&ivideo->sisfb_heap == sisfb_heap) + sis_int_malloc(ivideo, req); + else + req->offset = req->size = 0; +} void -sis_free(u32 base) +sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + + sis_int_malloc(ivideo, req); +} + +/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */ + +static void +sis_int_free(struct sis_video_info *ivideo, u32 base) { - struct sis_video_info *ivideo = sisfb_heap.vinfo; - SIS_OH *poh; + struct SIS_OH *poh; - if((!ivideo) || (ivideo->havenoheap)) return; + if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap)) + return; - poh = sisfb_poh_free((u32)base); + poh = sisfb_poh_free(&ivideo->sisfb_heap, base); if(poh == NULL) { DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n", @@ -3376,8 +3565,62 @@ sis_free(u32 base) } } +void +sis_free(u32 base) +{ + struct sis_video_info *ivideo = sisfb_heap->vinfo; + + sis_int_free(ivideo, base); +} + +void +sis_free_new(struct pci_dev *pdev, u32 base) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + + sis_int_free(ivideo, base); +} + /* --------------------- SetMode routines ------------------------- */ +static void +sisfb_check_engine_and_sync(struct sis_video_info *ivideo) +{ + u8 cr30, cr31; + + /* Check if MMIO and engines are enabled, + * and sync in case they are. Can't use + * ivideo->accel here, as this might have + * been changed before this is called. + */ + inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30); + inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31); + /* MMIO and 2D/3D engine enabled? */ + if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) { +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { + /* Don't care about TurboQueue. It's + * enough to know that the engines + * are enabled + */ + sisfb_syncaccel(ivideo); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if(ivideo->sisvga_engine == SIS_315_VGA) { + /* Check that any queue mode is + * enabled, and that the queue + * is not in the state of "reset" + */ + inSISIDXREG(SISSR, 0x26, cr30); + if((cr30 & 0xe0) && (!(cr30 & 0x01))) { + sisfb_syncaccel(ivideo); + } + } +#endif + } +} + static void sisfb_pre_setmode(struct sis_video_info *ivideo) { @@ -3386,6 +3629,8 @@ sisfb_pre_setmode(struct sis_video_info *ivideo) ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2); + outSISIDXREG(SISSR, 0x05, 0x86); + inSISIDXREG(SISCR, 0x31, cr31); cr31 &= ~0x60; cr31 |= 0x04; @@ -3413,41 +3658,43 @@ sisfb_pre_setmode(struct sis_video_info *ivideo) SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE); SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE); + ivideo->curFSTN = ivideo->curDSTN = 0; switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { case CRT2_TV: cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */ - if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) { + if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) { #ifdef CONFIG_FB_SIS_315 - if(ivideo->chip >= SIS_661) { - cr38 |= 0x04; - if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20; + if(ivideo->chip >= SIS_661) { + cr38 |= 0x04; + if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20; else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40; else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60; cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE; cr35 &= ~0x01; ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL)); - } else if(ivideo->sisvga_engine == SIS_315_VGA) { - cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE); + } else if(ivideo->sisvga_engine == SIS_315_VGA) { + cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE); cr38 |= 0x08; - if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10; + if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10; else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20; else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30; cr31 &= ~0x01; ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL)); - } -#endif - } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) { - if(ivideo->chip >= SIS_661) { - cr38 |= 0x04; - cr35 |= 0x60; - } else { - cr30 |= 0x80; - } + } +#endif + } else if((ivideo->vbflags & TV_HIVISION) && + (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) { + if(ivideo->chip >= SIS_661) { + cr38 |= 0x04; + cr35 |= 0x60; + } else { + cr30 |= 0x80; + } cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE; - cr31 |= 0x01; - cr35 |= 0x01; + cr31 |= 0x01; + cr35 |= 0x01; ivideo->currentvbflags |= TV_HIVISION; } else if(ivideo->vbflags & TV_SCART) { cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE); @@ -3466,8 +3713,8 @@ sisfb_pre_setmode(struct sis_video_info *ivideo) } cr31 |= SIS_DRIVER_MODE; - if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) { - if(ivideo->vbflags & TV_PAL) { + if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) { + if(ivideo->vbflags & TV_PAL) { cr31 |= 0x01; cr35 |= 0x01; ivideo->currentvbflags |= TV_PAL; if(ivideo->vbflags & TV_PALM) { @@ -3476,14 +3723,14 @@ sisfb_pre_setmode(struct sis_video_info *ivideo) } else if(ivideo->vbflags & TV_PALN) { cr38 |= 0x80; cr35 |= 0x08; ivideo->currentvbflags |= TV_PALN; - } - } else { + } + } else { cr31 &= ~0x01; cr35 &= ~0x01; ivideo->currentvbflags |= TV_NTSC; if(ivideo->vbflags & TV_NTSCJ) { cr38 |= 0x40; cr35 |= 0x02; ivideo->currentvbflags |= TV_NTSCJ; - } + } } } break; @@ -3493,6 +3740,8 @@ sisfb_pre_setmode(struct sis_video_info *ivideo) cr31 |= SIS_DRIVER_MODE; SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn); SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn); + ivideo->curFSTN = ivideo->sisfb_fstn; + ivideo->curDSTN = ivideo->sisfb_dstn; break; case CRT2_VGA: @@ -3525,9 +3774,9 @@ sisfb_pre_setmode(struct sis_video_info *ivideo) } outSISIDXREG(SISCR, 0x31, cr31); - if(ivideo->accel) sisfb_syncaccel(ivideo); - ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem; + + sisfb_check_engine_and_sync(ivideo); } /* Fix SR11 for 661 and later */ @@ -3535,125 +3784,129 @@ sisfb_pre_setmode(struct sis_video_info *ivideo) static void sisfb_fixup_SR11(struct sis_video_info *ivideo) { - u8 tmpreg; - - if(ivideo->chip >= SIS_661) { - inSISIDXREG(SISSR,0x11,tmpreg); - if(tmpreg & 0x20) { - inSISIDXREG(SISSR,0x3e,tmpreg); - tmpreg = (tmpreg + 1) & 0xff; - outSISIDXREG(SISSR,0x3e,tmpreg); - inSISIDXREG(SISSR,0x11,tmpreg); - } - if(tmpreg & 0xf0) { - andSISIDXREG(SISSR,0x11,0x0f); - } - } + u8 tmpreg; + + if(ivideo->chip >= SIS_661) { + inSISIDXREG(SISSR,0x11,tmpreg); + if(tmpreg & 0x20) { + inSISIDXREG(SISSR,0x3e,tmpreg); + tmpreg = (tmpreg + 1) & 0xff; + outSISIDXREG(SISSR,0x3e,tmpreg); + inSISIDXREG(SISSR,0x11,tmpreg); + } + if(tmpreg & 0xf0) { + andSISIDXREG(SISSR,0x11,0x0f); + } + } } #endif -static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val) +static void +sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val) { - if(val > 32) val = 32; - if(val < -32) val = -32; - ivideo->tvxpos = val; + if(val > 32) val = 32; + if(val < -32) val = -32; + ivideo->tvxpos = val; - if(ivideo->sisfblocked) return; - if(!ivideo->modechanged) return; + if(ivideo->sisfblocked) return; + if(!ivideo->modechanged) return; - if(ivideo->currentvbflags & CRT2_TV) { + if(ivideo->currentvbflags & CRT2_TV) { - if(ivideo->vbflags & VB_CHRONTEL) { + if(ivideo->vbflags2 & VB2_CHRONTEL) { - int x = ivideo->tvx; + int x = ivideo->tvx; - switch(ivideo->chronteltype) { - case 1: - x += val; - if(x < 0) x = 0; - outSISIDXREG(SISSR,0x05,0x86); - SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a)); - SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD); - break; - case 2: - /* Not supported by hardware */ - break; - } - - } else if(ivideo->vbflags & VB_SISBRIDGE) { - - u8 p2_1f,p2_20,p2_2b,p2_42,p2_43; - unsigned short temp; - - p2_1f = ivideo->p2_1f; - p2_20 = ivideo->p2_20; - p2_2b = ivideo->p2_2b; - p2_42 = ivideo->p2_42; - p2_43 = ivideo->p2_43; - - temp = p2_1f | ((p2_20 & 0xf0) << 4); - temp += (val * 2); - p2_1f = temp & 0xff; - p2_20 = (temp & 0xf00) >> 4; - p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f; - temp = p2_43 | ((p2_42 & 0xf0) << 4); - temp += (val * 2); - p2_43 = temp & 0xff; - p2_42 = (temp & 0xf00) >> 4; - outSISIDXREG(SISPART2,0x1f,p2_1f); - setSISIDXREG(SISPART2,0x20,0x0F,p2_20); - setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b); - setSISIDXREG(SISPART2,0x42,0x0F,p2_42); - outSISIDXREG(SISPART2,0x43,p2_43); - } - } + switch(ivideo->chronteltype) { + case 1: + x += val; + if(x < 0) x = 0; + outSISIDXREG(SISSR,0x05,0x86); + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff)); + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD); + break; + case 2: + /* Not supported by hardware */ + break; + } + + } else if(ivideo->vbflags2 & VB2_SISBRIDGE) { + + u8 p2_1f,p2_20,p2_2b,p2_42,p2_43; + unsigned short temp; + + p2_1f = ivideo->p2_1f; + p2_20 = ivideo->p2_20; + p2_2b = ivideo->p2_2b; + p2_42 = ivideo->p2_42; + p2_43 = ivideo->p2_43; + + temp = p2_1f | ((p2_20 & 0xf0) << 4); + temp += (val * 2); + p2_1f = temp & 0xff; + p2_20 = (temp & 0xf00) >> 4; + p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f; + temp = p2_43 | ((p2_42 & 0xf0) << 4); + temp += (val * 2); + p2_43 = temp & 0xff; + p2_42 = (temp & 0xf00) >> 4; + outSISIDXREG(SISPART2,0x1f,p2_1f); + setSISIDXREG(SISPART2,0x20,0x0F,p2_20); + setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b); + setSISIDXREG(SISPART2,0x42,0x0F,p2_42); + outSISIDXREG(SISPART2,0x43,p2_43); + } + } } -static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val) +static void +sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val) { - if(val > 32) val = 32; - if(val < -32) val = -32; - ivideo->tvypos = val; - - if(ivideo->sisfblocked) return; - if(!ivideo->modechanged) return; - - if(ivideo->currentvbflags & CRT2_TV) { - - if(ivideo->vbflags & VB_CHRONTEL) { - - int y = ivideo->tvy; - - switch(ivideo->chronteltype) { - case 1: - y -= val; - if(y < 0) y = 0; - outSISIDXREG(SISSR,0x05,0x86); - SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b)); - SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE); - break; - case 2: - /* Not supported by hardware */ - break; - } - - } else if(ivideo->vbflags & VB_SISBRIDGE) { - - char p2_01, p2_02; - val /= 2; - p2_01 = ivideo->p2_01; - p2_02 = ivideo->p2_02; - - p2_01 += val; - p2_02 += val; - while((p2_01 <= 0) || (p2_02 <= 0)) { - p2_01 += 2; - p2_02 += 2; - } - outSISIDXREG(SISPART2,0x01,p2_01); - outSISIDXREG(SISPART2,0x02,p2_02); - } - } + if(val > 32) val = 32; + if(val < -32) val = -32; + ivideo->tvypos = val; + + if(ivideo->sisfblocked) return; + if(!ivideo->modechanged) return; + + if(ivideo->currentvbflags & CRT2_TV) { + + if(ivideo->vbflags2 & VB2_CHRONTEL) { + + int y = ivideo->tvy; + + switch(ivideo->chronteltype) { + case 1: + y -= val; + if(y < 0) y = 0; + outSISIDXREG(SISSR,0x05,0x86); + SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff)); + SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE); + break; + case 2: + /* Not supported by hardware */ + break; + } + + } else if(ivideo->vbflags2 & VB2_SISBRIDGE) { + + char p2_01, p2_02; + val /= 2; + p2_01 = ivideo->p2_01; + p2_02 = ivideo->p2_02; + + p2_01 += val; + p2_02 += val; + if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) { + while((p2_01 <= 0) || (p2_02 <= 0)) { + p2_01 += 2; + p2_02 += 2; + } + } + outSISIDXREG(SISPART2,0x01,p2_01); + outSISIDXREG(SISPART2,0x02,p2_02); + } + } } static void @@ -3668,207 +3921,172 @@ sisfb_post_setmode(struct sis_video_info *ivideo) u8 reg1; #endif - outSISIDXREG(SISSR,0x05,0x86); + outSISIDXREG(SISSR, 0x05, 0x86); #ifdef CONFIG_FB_SIS_315 sisfb_fixup_SR11(ivideo); #endif /* Now we actually HAVE changed the display mode */ - ivideo->modechanged = 1; + ivideo->modechanged = 1; /* We can't switch off CRT1 if bridge is in slave mode */ - if(ivideo->vbflags & VB_VIDEOBRIDGE) { + if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) { if(sisfb_bridgeisslave(ivideo)) doit = FALSE; - } else ivideo->sisfb_crt1off = 0; + } else + ivideo->sisfb_crt1off = 0; #ifdef CONFIG_FB_SIS_300 if(ivideo->sisvga_engine == SIS_300_VGA) { - if((ivideo->sisfb_crt1off) && (doit)) { - crt1isoff = TRUE; - reg = 0x00; - } else { - crt1isoff = FALSE; - reg = 0x80; - } - setSISIDXREG(SISCR, 0x17, 0x7f, reg); + if((ivideo->sisfb_crt1off) && (doit)) { + crt1isoff = TRUE; + reg = 0x00; + } else { + crt1isoff = FALSE; + reg = 0x80; + } + setSISIDXREG(SISCR, 0x17, 0x7f, reg); } #endif #ifdef CONFIG_FB_SIS_315 if(ivideo->sisvga_engine == SIS_315_VGA) { - if((ivideo->sisfb_crt1off) && (doit)) { - crt1isoff = TRUE; - reg = 0x40; - reg1 = 0xc0; - } else { - crt1isoff = FALSE; - reg = 0x00; - reg1 = 0x00; - - } - setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg); - setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1); + if((ivideo->sisfb_crt1off) && (doit)) { + crt1isoff = TRUE; + reg = 0x40; + reg1 = 0xc0; + } else { + crt1isoff = FALSE; + reg = 0x00; + reg1 = 0x00; + } + setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg); + setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1); } #endif if(crt1isoff) { - ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1; - ivideo->currentvbflags |= VB_SINGLE_MODE; + ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1; + ivideo->currentvbflags |= VB_SINGLE_MODE; } else { - ivideo->currentvbflags |= VB_DISPTYPE_CRT1; - if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) { - ivideo->currentvbflags |= VB_MIRROR_MODE; - } else { - ivideo->currentvbflags |= VB_SINGLE_MODE; - } + ivideo->currentvbflags |= VB_DISPTYPE_CRT1; + if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) { + ivideo->currentvbflags |= VB_MIRROR_MODE; + } else { + ivideo->currentvbflags |= VB_SINGLE_MODE; + } } - andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04); + andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04); if(ivideo->currentvbflags & CRT2_TV) { - if(ivideo->vbflags & VB_SISBRIDGE) { - inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f); - inSISIDXREG(SISPART2,0x20,ivideo->p2_20); - inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b); - inSISIDXREG(SISPART2,0x42,ivideo->p2_42); - inSISIDXREG(SISPART2,0x43,ivideo->p2_43); - inSISIDXREG(SISPART2,0x01,ivideo->p2_01); - inSISIDXREG(SISPART2,0x02,ivideo->p2_02); - } else if(ivideo->vbflags & VB_CHRONTEL) { - if(ivideo->chronteltype == 1) { - ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a); - ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8); - ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b); - ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8); - } - } + if(ivideo->vbflags2 & VB2_SISBRIDGE) { + inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f); + inSISIDXREG(SISPART2,0x20,ivideo->p2_20); + inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b); + inSISIDXREG(SISPART2,0x42,ivideo->p2_42); + inSISIDXREG(SISPART2,0x43,ivideo->p2_43); + inSISIDXREG(SISPART2,0x01,ivideo->p2_01); + inSISIDXREG(SISPART2,0x02,ivideo->p2_02); + } else if(ivideo->vbflags2 & VB2_CHRONTEL) { + if(ivideo->chronteltype == 1) { + ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a); + ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8); + ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b); + ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8); + } + } } if(ivideo->tvxpos) { - sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos); + sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos); } if(ivideo->tvypos) { - sisfb_set_TVyposoffset(ivideo, ivideo->tvypos); + sisfb_set_TVyposoffset(ivideo, ivideo->tvypos); } - if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) { /* Set filter for SiS301 */ + /* Eventually sync engines */ + sisfb_check_engine_and_sync(ivideo); - unsigned char filter_tb = 0; + /* (Re-)Initialize chip engines */ + if(ivideo->accel) { + sisfb_engine_init(ivideo); + } else { + ivideo->engineok = 0; + } +} - switch (ivideo->video_width) { - case 320: - filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12; - break; - case 640: - filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13; - break; - case 720: - filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14; - break; - case 400: - case 800: - filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15; - break; - default: - ivideo->sisfb_filter = -1; - break; - } +static int +sisfb_reset_mode(struct sis_video_info *ivideo) +{ + if(sisfb_set_mode(ivideo, 0)) + return 1; - orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01); + sisfb_set_pitch(ivideo); + sisfb_set_base_CRT1(ivideo, ivideo->current_base); + sisfb_set_base_CRT2(ivideo, ivideo->current_base); - if(ivideo->vbflags & TV_NTSC) { - - andSISIDXREG(SISPART2, 0x3a, 0x1f); - - if (ivideo->vbflags & TV_SVIDEO) { - - andSISIDXREG(SISPART2, 0x30, 0xdf); - - } else if (ivideo->vbflags & TV_AVIDEO) { - - orSISIDXREG(SISPART2, 0x30, 0x20); - - switch (ivideo->video_width) { - case 640: - outSISIDXREG(SISPART2, 0x35, 0xEB); - outSISIDXREG(SISPART2, 0x36, 0x04); - outSISIDXREG(SISPART2, 0x37, 0x25); - outSISIDXREG(SISPART2, 0x38, 0x18); - break; - case 720: - outSISIDXREG(SISPART2, 0x35, 0xEE); - outSISIDXREG(SISPART2, 0x36, 0x0C); - outSISIDXREG(SISPART2, 0x37, 0x22); - outSISIDXREG(SISPART2, 0x38, 0x08); - break; - case 400: - case 800: - outSISIDXREG(SISPART2, 0x35, 0xEB); - outSISIDXREG(SISPART2, 0x36, 0x15); - outSISIDXREG(SISPART2, 0x37, 0x25); - outSISIDXREG(SISPART2, 0x38, 0xF6); - break; - } - } + return 0; +} + +static void +sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command) +{ + int mycrt1off; - } else if(ivideo->vbflags & TV_PAL) { - - andSISIDXREG(SISPART2, 0x3A, 0x1F); - - if (ivideo->vbflags & TV_SVIDEO) { - - andSISIDXREG(SISPART2, 0x30, 0xDF); - - } else if (ivideo->vbflags & TV_AVIDEO) { - - orSISIDXREG(SISPART2, 0x30, 0x20); - - switch (ivideo->video_width) { - case 640: - outSISIDXREG(SISPART2, 0x35, 0xF1); - outSISIDXREG(SISPART2, 0x36, 0xF7); - outSISIDXREG(SISPART2, 0x37, 0x1F); - outSISIDXREG(SISPART2, 0x38, 0x32); - break; - case 720: - outSISIDXREG(SISPART2, 0x35, 0xF3); - outSISIDXREG(SISPART2, 0x36, 0x00); - outSISIDXREG(SISPART2, 0x37, 0x1D); - outSISIDXREG(SISPART2, 0x38, 0x20); - break; - case 400: - case 800: - outSISIDXREG(SISPART2, 0x35, 0xFC); - outSISIDXREG(SISPART2, 0x36, 0xFB); - outSISIDXREG(SISPART2, 0x37, 0x14); - outSISIDXREG(SISPART2, 0x38, 0x2A); - break; + switch(sisfb_command->sisfb_cmd) { + case SISFB_CMD_GETVBFLAGS: + if(!ivideo->modechanged) { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY; + } else { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK; + sisfb_command->sisfb_result[1] = ivideo->currentvbflags; + sisfb_command->sisfb_result[2] = ivideo->vbflags2; + } + break; + case SISFB_CMD_SWITCHCRT1: + /* arg[0]: 0 = off, 1 = on, 99 = query */ + if(!ivideo->modechanged) { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY; + } else if(sisfb_command->sisfb_arg[0] == 99) { + /* Query */ + sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1; + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK; + } else if(ivideo->sisfblocked) { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED; + } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) && + (sisfb_command->sisfb_arg[0] == 0)) { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2; + } else { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK; + mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1; + if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) || + ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) { + ivideo->sisfb_crt1off = mycrt1off; + if(sisfb_reset_mode(ivideo)) { + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER; } } + sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1; } - - if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) { - outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0])); - outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1])); - outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2])); - outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3])); - } - + break; + /* more to come */ + default: + sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN; + printk(KERN_ERR "sisfb: Unknown command 0x%x\n", + sisfb_command->sisfb_cmd); } } #ifndef MODULE -SISINITSTATIC int __init sisfb_setup(char *options) +SISINITSTATIC int __init +sisfb_setup(char *options) { char *this_opt; - - sisfb_setdefaultparms(); - printk(KERN_DEBUG "sisfb: Options %s\n", options); + sisfb_setdefaultparms(); - if(!options || !(*options)) { + if(!options || !(*options)) return 0; - } while((this_opt = strsep(&options, ",")) != NULL) { @@ -3880,9 +4098,9 @@ SISINITSTATIC int __init sisfb_setup(char *options) /* Need to check crt2 type first for fstn/dstn */ sisfb_search_crt2type(this_opt + 14); } else if(!strnicmp(this_opt, "tvmode:",7)) { - sisfb_search_tvstd(this_opt + 7); - } else if(!strnicmp(this_opt, "tvstandard:",11)) { sisfb_search_tvstd(this_opt + 7); + } else if(!strnicmp(this_opt, "tvstandard:",11)) { + sisfb_search_tvstd(this_opt + 11); } else if(!strnicmp(this_opt, "mode:", 5)) { sisfb_search_mode(this_opt + 5, FALSE); } else if(!strnicmp(this_opt, "vesa:", 5)) { @@ -3892,74 +4110,72 @@ SISINITSTATIC int __init sisfb_setup(char *options) sisfb_inverse = 1; /* fb_invert_cmaps(); */ } else if(!strnicmp(this_opt, "font:", 5)) { - if(strlen(this_opt + 5) < 40) { + if(strlen(this_opt + 5) < 40) { strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1); sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0'; } #endif } else if(!strnicmp(this_opt, "rate:", 5)) { sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0); - } else if(!strnicmp(this_opt, "filter:", 7)) { - sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0); } else if(!strnicmp(this_opt, "forcecrt1:", 10)) { sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0); - } else if(!strnicmp(this_opt, "mem:",4)) { - sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0); + } else if(!strnicmp(this_opt, "mem:",4)) { + sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0); } else if(!strnicmp(this_opt, "pdc:", 4)) { - sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0); + sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0); } else if(!strnicmp(this_opt, "pdc1:", 5)) { - sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0); + sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0); } else if(!strnicmp(this_opt, "noaccel", 7)) { sisfb_accel = 0; } else if(!strnicmp(this_opt, "accel", 5)) { sisfb_accel = -1; } else if(!strnicmp(this_opt, "noypan", 6)) { - sisfb_ypan = 0; + sisfb_ypan = 0; } else if(!strnicmp(this_opt, "ypan", 4)) { - sisfb_ypan = -1; + sisfb_ypan = -1; } else if(!strnicmp(this_opt, "nomax", 5)) { - sisfb_max = 0; + sisfb_max = 0; } else if(!strnicmp(this_opt, "max", 3)) { - sisfb_max = -1; + sisfb_max = -1; } else if(!strnicmp(this_opt, "userom:", 7)) { sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0); } else if(!strnicmp(this_opt, "useoem:", 7)) { sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0); } else if(!strnicmp(this_opt, "nocrt2rate", 10)) { sisfb_nocrt2rate = 1; - } else if(!strnicmp(this_opt, "scalelcd:", 9)) { - unsigned long temp = 2; - temp = simple_strtoul(this_opt + 9, NULL, 0); - if((temp == 0) || (temp == 1)) { + } else if(!strnicmp(this_opt, "scalelcd:", 9)) { + unsigned long temp = 2; + temp = simple_strtoul(this_opt + 9, NULL, 0); + if((temp == 0) || (temp == 1)) { sisfb_scalelcd = temp ^ 1; - } + } } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) { - int temp = 0; - temp = (int)simple_strtol(this_opt + 13, NULL, 0); - if((temp >= -32) && (temp <= 32)) { + int temp = 0; + temp = (int)simple_strtol(this_opt + 13, NULL, 0); + if((temp >= -32) && (temp <= 32)) { sisfb_tvxposoffset = temp; - } + } } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) { - int temp = 0; - temp = (int)simple_strtol(this_opt + 13, NULL, 0); - if((temp >= -32) && (temp <= 32)) { + int temp = 0; + temp = (int)simple_strtol(this_opt + 13, NULL, 0); + if((temp >= -32) && (temp <= 32)) { sisfb_tvyposoffset = temp; - } + } } else if(!strnicmp(this_opt, "specialtiming:", 14)) { sisfb_search_specialtiming(this_opt + 14); } else if(!strnicmp(this_opt, "lvdshl:", 7)) { - int temp = 4; - temp = simple_strtoul(this_opt + 7, NULL, 0); - if((temp >= 0) && (temp <= 3)) { + int temp = 4; + temp = simple_strtoul(this_opt + 7, NULL, 0); + if((temp >= 0) && (temp <= 3)) { sisfb_lvdshl = temp; - } + } } else if(this_opt[0] >= '0' && this_opt[0] <= '9') { sisfb_search_mode(this_opt, TRUE); #if !defined(__i386__) && !defined(__x86_64__) - } else if(!strnicmp(this_opt, "resetcard", 9)) { - sisfb_resetcard = 1; + } else if(!strnicmp(this_opt, "resetcard", 9)) { + sisfb_resetcard = 1; } else if(!strnicmp(this_opt, "videoram:", 9)) { - sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0); + sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0); #endif } else { printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt); @@ -3967,819 +4183,1706 @@ SISINITSTATIC int __init sisfb_setup(char *options) } + return 0; +} +#endif + +static int __devinit +sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo) +{ + SIS_IOTYPE1 *rom; + int romptr; + + if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) + return 0; + + romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8)); + if(romptr > (0x10000 - 8)) + return 0; + + rom = rom_base + romptr; + + if((readb(rom) != 'P') || (readb(rom + 1) != 'C') || + (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) + return 0; + + if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor) + return 0; + + if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id) + return 0; + + return 1; +} + +static unsigned char * __devinit +sisfb_find_rom(struct pci_dev *pdev) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + SIS_IOTYPE1 *rom_base; + unsigned char *myrombase = NULL; + u32 temp; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) + size_t romsize; + + /* First, try the official pci ROM functions (except + * on integrated chipsets which have no ROM). + */ + + if(!ivideo->nbridge) { + + if((rom_base = pci_map_rom(pdev, &romsize))) { + + if(sisfb_check_rom(rom_base, ivideo)) { + + if((myrombase = vmalloc(65536))) { + + /* Work around bug in pci/rom.c: Folks forgot to check + * whether the size retrieved from the BIOS image eventually + * is larger than the mapped size + */ + if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize) + romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE); + + memcpy_fromio(myrombase, rom_base, + (romsize > 65536) ? 65536 : romsize); + } + } + pci_unmap_rom(pdev, rom_base); + } + } + + if(myrombase) return myrombase; +#endif + + /* Otherwise do it the conventional way. */ + +#if defined(__i386__) || defined(__x86_64__) + + for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) { + + rom_base = ioremap(temp, 65536); + if(!rom_base) + continue; + + if(!sisfb_check_rom(rom_base, ivideo)) { + iounmap(rom_base); + continue; + } + + if((myrombase = vmalloc(65536))) + memcpy_fromio(myrombase, rom_base, 65536); + + iounmap(rom_base); + break; + + } + +#else + + pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, + (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE); + + rom_base = ioremap(ivideo->video_base, 65536); + if(rom_base) { + if(sisfb_check_rom(rom_base, ivideo)) { + if((myrombase = vmalloc(65536))) + memcpy_fromio(myrombase, rom_base, 65536); + } + iounmap(rom_base); + } + + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp); + +#endif + + return myrombase; +} + +static void __devinit +sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize, + unsigned int min) +{ + ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize)); + + if(!ivideo->video_vbase) { + printk(KERN_ERR + "sisfb: Unable to map maximum video RAM for size detection\n"); + (*mapsize) >>= 1; + while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) { + (*mapsize) >>= 1; + if((*mapsize) < (min << 20)) + break; + } + if(ivideo->video_vbase) { + printk(KERN_ERR + "sisfb: Video RAM size detection limited to %dMB\n", + (int)((*mapsize) >> 20)); + } + } +} + +#ifdef CONFIG_FB_SIS_300 +static int __devinit +sisfb_post_300_buswidth(struct sis_video_info *ivideo) +{ + SIS_IOTYPE1 *FBAddress = ivideo->video_vbase; + unsigned short temp; + unsigned char reg; + int i, j; + + andSISIDXREG(SISSR, 0x15, 0xFB); + orSISIDXREG(SISSR, 0x15, 0x04); + outSISIDXREG(SISSR, 0x13, 0x00); + outSISIDXREG(SISSR, 0x14, 0xBF); + + for(i = 0; i < 2; i++) { + temp = 0x1234; + for(j = 0; j < 4; j++) { + writew(temp, FBAddress); + if(readw(FBAddress) == temp) + break; + orSISIDXREG(SISSR, 0x3c, 0x01); + inSISIDXREG(SISSR, 0x05, reg); + inSISIDXREG(SISSR, 0x05, reg); + andSISIDXREG(SISSR, 0x3c, 0xfe); + inSISIDXREG(SISSR, 0x05, reg); + inSISIDXREG(SISSR, 0x05, reg); + temp++; + } + } + + writel(0x01234567L, FBAddress); + writel(0x456789ABL, (FBAddress + 4)); + writel(0x89ABCDEFL, (FBAddress + 8)); + writel(0xCDEF0123L, (FBAddress + 12)); + + inSISIDXREG(SISSR, 0x3b, reg); + if(reg & 0x01) { + if(readl((FBAddress + 12)) == 0xCDEF0123L) + return 4; /* Channel A 128bit */ + } + + if(readl((FBAddress + 4)) == 0x456789ABL) + return 2; /* Channel B 64bit */ + + return 1; /* 32bit */ +} + +static int __devinit +sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth, + int PseudoRankCapacity, int PseudoAdrPinCount, + unsigned int mapsize) +{ + SIS_IOTYPE1 *FBAddr = ivideo->video_vbase; + unsigned short sr14; + unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid; + unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage; + static const unsigned short SiS_DRAMType[17][5] = { + {0x0C,0x0A,0x02,0x40,0x39}, + {0x0D,0x0A,0x01,0x40,0x48}, + {0x0C,0x09,0x02,0x20,0x35}, + {0x0D,0x09,0x01,0x20,0x44}, + {0x0C,0x08,0x02,0x10,0x31}, + {0x0D,0x08,0x01,0x10,0x40}, + {0x0C,0x0A,0x01,0x20,0x34}, + {0x0C,0x09,0x01,0x08,0x32}, + {0x0B,0x08,0x02,0x08,0x21}, + {0x0C,0x08,0x01,0x08,0x30}, + {0x0A,0x08,0x02,0x04,0x11}, + {0x0B,0x0A,0x01,0x10,0x28}, + {0x09,0x08,0x02,0x02,0x01}, + {0x0B,0x09,0x01,0x08,0x24}, + {0x0B,0x08,0x01,0x04,0x20}, + {0x0A,0x08,0x01,0x02,0x10}, + {0x09,0x08,0x01,0x01,0x00} + }; + + for(k = 0; k <= 16; k++) { + + RankCapacity = buswidth * SiS_DRAMType[k][3]; + + if(RankCapacity != PseudoRankCapacity) + continue; + + if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount) + continue; + + BankNumHigh = RankCapacity * 16 * iteration - 1; + if(iteration == 3) { /* Rank No */ + BankNumMid = RankCapacity * 16 - 1; + } else { + BankNumMid = RankCapacity * 16 * iteration / 2 - 1; + } + + PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4; + PhysicalAdrHigh = BankNumHigh; + PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity; + PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh; + + andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */ + orSISIDXREG(SISSR, 0x15, 0x04); /* Test */ + sr14 = (SiS_DRAMType[k][3] * buswidth) - 1; + if(buswidth == 4) sr14 |= 0x80; + else if(buswidth == 2) sr14 |= 0x40; + outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]); + outSISIDXREG(SISSR, 0x14, sr14); + + BankNumHigh <<= 16; + BankNumMid <<= 16; + + if((BankNumHigh + PhysicalAdrHigh >= mapsize) || + (BankNumMid + PhysicalAdrHigh >= mapsize) || + (BankNumHigh + PhysicalAdrHalfPage >= mapsize) || + (BankNumHigh + PhysicalAdrOtherPage >= mapsize)) + continue; + + /* Write data */ + writew(((unsigned short)PhysicalAdrHigh), + (FBAddr + BankNumHigh + PhysicalAdrHigh)); + writew(((unsigned short)BankNumMid), + (FBAddr + BankNumMid + PhysicalAdrHigh)); + writew(((unsigned short)PhysicalAdrHalfPage), + (FBAddr + BankNumHigh + PhysicalAdrHalfPage)); + writew(((unsigned short)PhysicalAdrOtherPage), + (FBAddr + BankNumHigh + PhysicalAdrOtherPage)); + + /* Read data */ + if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh) + return 1; + } + + return 0; +} + +static void __devinit +sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + int i, j, buswidth; + int PseudoRankCapacity, PseudoAdrPinCount; + + buswidth = sisfb_post_300_buswidth(ivideo); + + for(i = 6; i >= 0; i--) { + PseudoRankCapacity = 1 << i; + for(j = 4; j >= 1; j--) { + PseudoAdrPinCount = 15 - j; + if((PseudoRankCapacity * j) <= 64) { + if(sisfb_post_300_rwtest(ivideo, + j, + buswidth, + PseudoRankCapacity, + PseudoAdrPinCount, + mapsize)) + return; + } + } + } +} + +static void __devinit +sisfb_post_sis300(struct pci_dev *pdev) +{ + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase; + u8 reg, v1, v2, v3, v4, v5, v6, v7, v8; + u16 index, rindex, memtype = 0; + unsigned int mapsize; + + if(!ivideo->SiS_Pr.UseROM) + bios = NULL; + + outSISIDXREG(SISSR, 0x05, 0x86); + + if(bios) { + if(bios[0x52] & 0x80) { + memtype = bios[0x52]; + } else { + inSISIDXREG(SISSR, 0x3a, memtype); + } + memtype &= 0x07; + } + + v3 = 0x80; v6 = 0x80; + if(ivideo->revision_id <= 0x13) { + v1 = 0x44; v2 = 0x42; + v4 = 0x44; v5 = 0x42; + } else { + v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */ + v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */ + if(bios) { + index = memtype * 5; + rindex = index + 0x54; + v1 = bios[rindex++]; + v2 = bios[rindex++]; + v3 = bios[rindex++]; + rindex = index + 0x7c; + v4 = bios[rindex++]; + v5 = bios[rindex++]; + v6 = bios[rindex++]; + } + } + outSISIDXREG(SISSR, 0x28, v1); + outSISIDXREG(SISSR, 0x29, v2); + outSISIDXREG(SISSR, 0x2a, v3); + outSISIDXREG(SISSR, 0x2e, v4); + outSISIDXREG(SISSR, 0x2f, v5); + outSISIDXREG(SISSR, 0x30, v6); + + v1 = 0x10; + if(bios) + v1 = bios[0xa4]; + outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */ + + outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */ + + v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a; + v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00; + if(bios) { + memtype += 0xa5; + v1 = bios[memtype]; + v2 = bios[memtype + 8]; + v3 = bios[memtype + 16]; + v4 = bios[memtype + 24]; + v5 = bios[memtype + 32]; + v6 = bios[memtype + 40]; + v7 = bios[memtype + 48]; + v8 = bios[memtype + 56]; + } + if(ivideo->revision_id >= 0x80) + v3 &= 0xfd; + outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */ + outSISIDXREG(SISSR, 0x16, v2); + outSISIDXREG(SISSR, 0x17, v3); + outSISIDXREG(SISSR, 0x18, v4); + outSISIDXREG(SISSR, 0x19, v5); + outSISIDXREG(SISSR, 0x1a, v6); + outSISIDXREG(SISSR, 0x1b, v7); + outSISIDXREG(SISSR, 0x1c, v8); /* ---- */ + andSISIDXREG(SISSR, 0x15 ,0xfb); + orSISIDXREG(SISSR, 0x15, 0x04); + if(bios) { + if(bios[0x53] & 0x02) { + orSISIDXREG(SISSR, 0x19, 0x20); + } + } + v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */ + if(ivideo->revision_id >= 0x80) + v1 |= 0x01; + outSISIDXREG(SISSR, 0x1f, v1); + outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */ + v1 = 0xf6; v2 = 0x0d; v3 = 0x00; + if(bios) { + v1 = bios[0xe8]; + v2 = bios[0xe9]; + v3 = bios[0xea]; + } + outSISIDXREG(SISSR, 0x23, v1); + outSISIDXREG(SISSR, 0x24, v2); + outSISIDXREG(SISSR, 0x25, v3); + outSISIDXREG(SISSR, 0x21, 0x84); + outSISIDXREG(SISSR, 0x22, 0x00); + outSISIDXREG(SISCR, 0x37, 0x00); + orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */ + outSISIDXREG(SISPART1, 0x00, 0x00); + v1 = 0x40; v2 = 0x11; + if(bios) { + v1 = bios[0xec]; + v2 = bios[0xeb]; + } + outSISIDXREG(SISPART1, 0x02, v1); + + if(ivideo->revision_id >= 0x80) + v2 &= ~0x01; + + inSISIDXREG(SISPART4, 0x00, reg); + if((reg == 1) || (reg == 2)) { + outSISIDXREG(SISCR, 0x37, 0x02); + outSISIDXREG(SISPART2, 0x00, 0x1c); + v4 = 0x00; v5 = 0x00; v6 = 0x10; + if(ivideo->SiS_Pr.UseROM) { + v4 = bios[0xf5]; + v5 = bios[0xf6]; + v6 = bios[0xf7]; + } + outSISIDXREG(SISPART4, 0x0d, v4); + outSISIDXREG(SISPART4, 0x0e, v5); + outSISIDXREG(SISPART4, 0x10, v6); + outSISIDXREG(SISPART4, 0x0f, 0x3f); + inSISIDXREG(SISPART4, 0x01, reg); + if(reg >= 0xb0) { + inSISIDXREG(SISPART4, 0x23, reg); + reg &= 0x20; + reg <<= 1; + outSISIDXREG(SISPART4, 0x23, reg); + } + } else { + v2 &= ~0x10; + } + outSISIDXREG(SISSR, 0x32, v2); + + andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */ + + inSISIDXREG(SISSR, 0x16, reg); + reg &= 0xc3; + outSISIDXREG(SISCR, 0x35, reg); + outSISIDXREG(SISCR, 0x83, 0x00); +#if !defined(__i386__) && !defined(__x86_64__) + if(sisfb_videoram) { + outSISIDXREG(SISSR, 0x13, 0x28); /* ? */ + reg = ((sisfb_videoram >> 10) - 1) | 0x40; + outSISIDXREG(SISSR, 0x14, reg); + } else { +#endif + /* Need to map max FB size for finding out about RAM size */ + mapsize = 64 << 20; + sisfb_post_map_vram(ivideo, &mapsize, 4); + + if(ivideo->video_vbase) { + sisfb_post_300_ramsize(pdev, mapsize); + iounmap(ivideo->video_vbase); + } else { + printk(KERN_DEBUG + "sisfb: Failed to map memory for size detection, assuming 8MB\n"); + outSISIDXREG(SISSR, 0x13, 0x28); /* ? */ + outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */ + } +#if !defined(__i386__) && !defined(__x86_64__) + } +#endif + if(bios) { + v1 = bios[0xe6]; + v2 = bios[0xe7]; + } else { + inSISIDXREG(SISSR, 0x3a, reg); + if((reg & 0x30) == 0x30) { + v1 = 0x04; /* PCI */ + v2 = 0x92; + } else { + v1 = 0x14; /* AGP */ + v2 = 0xb2; + } + } + outSISIDXREG(SISSR, 0x21, v1); + outSISIDXREG(SISSR, 0x22, v2); + + /* Sense CRT1 */ + sisfb_sense_crt1(ivideo); + + /* Set default mode, don't clear screen */ + ivideo->SiS_Pr.SiS_UseOEM = FALSE; + SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE); + SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE); + ivideo->curFSTN = ivideo->curDSTN = 0; + ivideo->SiS_Pr.VideoMemorySize = 8 << 20; + SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80); + + outSISIDXREG(SISSR, 0x05, 0x86); + + /* Display off */ + orSISIDXREG(SISSR, 0x01, 0x20); + + /* Save mode number in CR34 */ + outSISIDXREG(SISCR, 0x34, 0x2e); + + /* Let everyone know what the current mode is */ + ivideo->modeprechange = 0x2e; +} +#endif + +#ifdef CONFIG_FB_SIS_315 +#if 0 +static void __devinit +sisfb_post_sis315330(struct pci_dev *pdev) +{ + /* TODO */ +} +#endif + +static void __devinit +sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay) +{ + unsigned int i; + u8 reg; + + for(i = 0; i <= (delay * 10 * 36); i++) { + inSISIDXREG(SISSR, 0x05, reg); + reg++; + } +} + +static int __devinit +sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev, + unsigned short pcivendor) +{ + struct pci_dev *pdev = NULL; + unsigned short temp; + int ret = 0; + + while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) { + temp = pdev->vendor; + SIS_PCI_PUT_DEVICE(pdev); + if(temp == pcivendor) { + ret = 1; + break; + } + } + + return ret; +} + +static int __devinit +sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta, + unsigned int enda, unsigned int mapsize) +{ + unsigned int pos; + int i; + + writel(0, ivideo->video_vbase); + + for(i = starta; i <= enda; i++) { + pos = 1 << i; + if(pos < mapsize) + writel(pos, ivideo->video_vbase + pos); + } + + sisfb_post_xgi_delay(ivideo, 150); + + if(readl(ivideo->video_vbase) != 0) + return 0; + + for(i = starta; i <= enda; i++) { + pos = 1 << i; + if(pos < mapsize) { + if(readl(ivideo->video_vbase + pos) != pos) + return 0; + } else + return 0; + } + + return 1; +} + +static void __devinit +sisfb_post_xgi_ramsize(struct sis_video_info *ivideo) +{ + unsigned int buswidth, ranksize, channelab, mapsize; + int i, j, k, l; + u8 reg, sr14; + static const u8 dramsr13[12 * 5] = { + 0x02, 0x0e, 0x0b, 0x80, 0x5d, + 0x02, 0x0e, 0x0a, 0x40, 0x59, + 0x02, 0x0d, 0x0b, 0x40, 0x4d, + 0x02, 0x0e, 0x09, 0x20, 0x55, + 0x02, 0x0d, 0x0a, 0x20, 0x49, + 0x02, 0x0c, 0x0b, 0x20, 0x3d, + 0x02, 0x0e, 0x08, 0x10, 0x51, + 0x02, 0x0d, 0x09, 0x10, 0x45, + 0x02, 0x0c, 0x0a, 0x10, 0x39, + 0x02, 0x0d, 0x08, 0x08, 0x41, + 0x02, 0x0c, 0x09, 0x08, 0x35, + 0x02, 0x0c, 0x08, 0x04, 0x31 + }; + static const u8 dramsr13_4[4 * 5] = { + 0x02, 0x0d, 0x09, 0x40, 0x45, + 0x02, 0x0c, 0x09, 0x20, 0x35, + 0x02, 0x0c, 0x08, 0x10, 0x31, + 0x02, 0x0b, 0x08, 0x08, 0x21 + }; + + /* Enable linear mode, disable 0xa0000 address decoding */ + /* We disable a0000 address decoding, because + * - if running on x86, if the card is disabled, it means + * that another card is in the system. We don't want + * to interphere with that primary card's textmode. + * - if running on non-x86, there usually is no VGA window + * at a0000. + */ + orSISIDXREG(SISSR, 0x20, (0x80 | 0x04)); + + /* Need to map max FB size for finding out about RAM size */ + mapsize = 256 << 20; + sisfb_post_map_vram(ivideo, &mapsize, 32); + + if(!ivideo->video_vbase) { + printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n"); + outSISIDXREG(SISSR, 0x13, 0x35); + outSISIDXREG(SISSR, 0x14, 0x41); + /* TODO */ + return; + } + + /* Non-interleaving */ + outSISIDXREG(SISSR, 0x15, 0x00); + /* No tiling */ + outSISIDXREG(SISSR, 0x1c, 0x00); + + if(ivideo->chip == XGI_20) { + + channelab = 1; + inSISIDXREG(SISCR, 0x97, reg); + if(!(reg & 0x01)) { /* Single 32/16 */ + buswidth = 32; + outSISIDXREG(SISSR, 0x13, 0xb1); + outSISIDXREG(SISSR, 0x14, 0x52); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x02; + if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) + goto bail_out; + + outSISIDXREG(SISSR, 0x13, 0x31); + outSISIDXREG(SISSR, 0x14, 0x42); + sisfb_post_xgi_delay(ivideo, 1); + if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize)) + goto bail_out; + + buswidth = 16; + outSISIDXREG(SISSR, 0x13, 0xb1); + outSISIDXREG(SISSR, 0x14, 0x41); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x01; + if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize)) + goto bail_out; + else + outSISIDXREG(SISSR, 0x13, 0x31); + } else { /* Dual 16/8 */ + buswidth = 16; + outSISIDXREG(SISSR, 0x13, 0xb1); + outSISIDXREG(SISSR, 0x14, 0x41); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x01; + if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize)) + goto bail_out; + + outSISIDXREG(SISSR, 0x13, 0x31); + outSISIDXREG(SISSR, 0x14, 0x31); + sisfb_post_xgi_delay(ivideo, 1); + if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize)) + goto bail_out; + + buswidth = 8; + outSISIDXREG(SISSR, 0x13, 0xb1); + outSISIDXREG(SISSR, 0x14, 0x30); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x00; + if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize)) + goto bail_out; + else + outSISIDXREG(SISSR, 0x13, 0x31); + } + + } else { /* XGI_40 */ + + inSISIDXREG(SISCR, 0x97, reg); + if(!(reg & 0x10)) { + inSISIDXREG(SISSR, 0x39, reg); + reg >>= 1; + } + + if(reg & 0x01) { /* DDRII */ + buswidth = 32; + if(ivideo->revision_id == 2) { + channelab = 2; + outSISIDXREG(SISSR, 0x13, 0xa1); + outSISIDXREG(SISSR, 0x14, 0x44); + sr14 = 0x04; + sisfb_post_xgi_delay(ivideo, 1); + if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) + goto bail_out; + + outSISIDXREG(SISSR, 0x13, 0x21); + outSISIDXREG(SISSR, 0x14, 0x34); + if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize)) + goto bail_out; + + channelab = 1; + outSISIDXREG(SISSR, 0x13, 0xa1); + outSISIDXREG(SISSR, 0x14, 0x40); + sr14 = 0x00; + if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize)) + goto bail_out; + + outSISIDXREG(SISSR, 0x13, 0x21); + outSISIDXREG(SISSR, 0x14, 0x30); + } else { + channelab = 3; + outSISIDXREG(SISSR, 0x13, 0xa1); + outSISIDXREG(SISSR, 0x14, 0x4c); + sr14 = 0x0c; + sisfb_post_xgi_delay(ivideo, 1); + if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize)) + goto bail_out; + + channelab = 2; + outSISIDXREG(SISSR, 0x14, 0x48); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x08; + if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) + goto bail_out; + + outSISIDXREG(SISSR, 0x13, 0x21); + outSISIDXREG(SISSR, 0x14, 0x3c); + sr14 = 0x0c; + + if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) { + channelab = 3; + } else { + channelab = 2; + outSISIDXREG(SISSR, 0x14, 0x38); + sr14 = 0x08; + } + } + sisfb_post_xgi_delay(ivideo, 1); + + } else { /* DDR */ + + buswidth = 64; + if(ivideo->revision_id == 2) { + channelab = 1; + outSISIDXREG(SISSR, 0x13, 0xa1); + outSISIDXREG(SISSR, 0x14, 0x52); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x02; + if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) + goto bail_out; + + outSISIDXREG(SISSR, 0x13, 0x21); + outSISIDXREG(SISSR, 0x14, 0x42); + } else { + channelab = 2; + outSISIDXREG(SISSR, 0x13, 0xa1); + outSISIDXREG(SISSR, 0x14, 0x5a); + sisfb_post_xgi_delay(ivideo, 1); + sr14 = 0x0a; + if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize)) + goto bail_out; + + outSISIDXREG(SISSR, 0x13, 0x21); + outSISIDXREG(SISSR, 0x14, 0x4a); + } + sisfb_post_xgi_delay(ivideo, 1); + + } + } + +bail_out: + setSISIDXREG(SISSR, 0x14, 0xf0, sr14); + sisfb_post_xgi_delay(ivideo, 1); + + j = (ivideo->chip == XGI_20) ? 5 : 9; + k = (ivideo->chip == XGI_20) ? 12 : 4; + + for(i = 0; i < k; i++) { + + reg = (ivideo->chip == XGI_20) ? + dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4]; + setSISIDXREG(SISSR, 0x13, 0x80, reg); + sisfb_post_xgi_delay(ivideo, 50); + + ranksize = (ivideo->chip == XGI_20) ? + dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3]; + + inSISIDXREG(SISSR, 0x13, reg); + if(reg & 0x80) ranksize <<= 1; + + if(ivideo->chip == XGI_20) { + if(buswidth == 16) ranksize <<= 1; + else if(buswidth == 32) ranksize <<= 2; + } else { + if(buswidth == 64) ranksize <<= 1; + } + + reg = 0; + l = channelab; + if(l == 3) l = 4; + if((ranksize * l) <= 256) { + while((ranksize >>= 1)) reg += 0x10; + } + + if(!reg) continue; + + setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0)); + sisfb_post_xgi_delay(ivideo, 1); + + if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) + break; + } + + iounmap(ivideo->video_vbase); +} +static void __devinit +sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb) +{ + u8 v1, v2, v3; + int index; + static const u8 cs90[8 * 3] = { + 0x16, 0x01, 0x01, + 0x3e, 0x03, 0x01, + 0x7c, 0x08, 0x01, + 0x79, 0x06, 0x01, + 0x29, 0x01, 0x81, + 0x5c, 0x23, 0x01, + 0x5c, 0x23, 0x01, + 0x5c, 0x23, 0x01 + }; + static const u8 csb8[8 * 3] = { + 0x5c, 0x23, 0x01, + 0x29, 0x01, 0x01, + 0x7c, 0x08, 0x01, + 0x79, 0x06, 0x01, + 0x29, 0x01, 0x81, + 0x5c, 0x23, 0x01, + 0x5c, 0x23, 0x01, + 0x5c, 0x23, 0x01 + }; - return 0; + regb = 0; /* ! */ + + index = regb * 3; + v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2]; + if(ivideo->haveXGIROM) { + v1 = ivideo->bios_abase[0x90 + index]; + v2 = ivideo->bios_abase[0x90 + index + 1]; + v3 = ivideo->bios_abase[0x90 + index + 2]; + } + outSISIDXREG(SISSR, 0x28, v1); + outSISIDXREG(SISSR, 0x29, v2); + outSISIDXREG(SISSR, 0x2a, v3); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + index = regb * 3; + v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2]; + if(ivideo->haveXGIROM) { + v1 = ivideo->bios_abase[0xb8 + index]; + v2 = ivideo->bios_abase[0xb8 + index + 1]; + v3 = ivideo->bios_abase[0xb8 + index + 2]; + } + outSISIDXREG(SISSR, 0x2e, v1); + outSISIDXREG(SISSR, 0x2f, v2); + outSISIDXREG(SISSR, 0x30, v3); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); } -#endif -static UCHAR * __devinit sis_find_rom(struct pci_dev *pdev) +static int __devinit +sisfb_post_xgi(struct pci_dev *pdev) { struct sis_video_info *ivideo = pci_get_drvdata(pdev); - USHORT pciid; - int romptr; - UCHAR *myrombase; - u32 temp; - SIS_IOTYPE1 *rom_base, *rom; + unsigned char *bios = ivideo->bios_abase; + struct pci_dev *mypdev = NULL; + const u8 *ptr, *ptr2; + u8 v1, v2, v3, v4, v5, reg, ramtype; + u32 rega, regb, regd; + int i, j, k, index; + static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 }; + static const u8 cs76[2] = { 0xa3, 0xfb }; + static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 }; + static const u8 cs158[8] = { + 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs160[8] = { + 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs168[8] = { + 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs128[3 * 8] = { + 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs148[2 * 8] = { + 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs31a[8 * 4] = { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs33a[8 * 4] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs45a[8 * 2] = { + 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs170[7 * 8] = { + 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs1a8[3 * 8] = { + 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs100[2 * 8] = { + 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 + }; - if(!(myrombase = vmalloc(65536))) return NULL; + /* VGA enable */ + reg = inSISREG(SISVGAENABLE) | 0x01; + outSISREG(SISVGAENABLE, reg); -#if defined(__i386__) || defined(__x86_64__) + /* Misc */ + reg = inSISREG(SISMISCR) | 0x01; + outSISREG(SISMISCW, reg); - for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) { + /* Unlock SR */ + outSISIDXREG(SISSR, 0x05, 0x86); + inSISIDXREG(SISSR, 0x05, reg); + if(reg != 0xa1) + return 0; - rom_base = ioremap(temp, 0x10000); - if(!rom_base) continue; + /* Clear some regs */ + for(i = 0; i < 0x22; i++) { + if(0x06 + i == 0x20) continue; + outSISIDXREG(SISSR, 0x06 + i, 0x00); + } + for(i = 0; i < 0x0b; i++) { + outSISIDXREG(SISSR, 0x31 + i, 0x00); + } + for(i = 0; i < 0x10; i++) { + outSISIDXREG(SISCR, 0x30 + i, 0x00); + } - if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) { - iounmap(rom_base); - continue; - } + ptr = cs78; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x78]; + } + for(i = 0; i < 3; i++) { + outSISIDXREG(SISSR, 0x23 + i, ptr[i]); + } - romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8)); - if(romptr > (0x10000 - 8)) { - iounmap(rom_base); - continue; - } + ptr = cs76; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x76]; + } + for(i = 0; i < 2; i++) { + outSISIDXREG(SISSR, 0x21 + i, ptr[i]); + } - rom = rom_base + romptr; + v1 = 0x18; v2 = 0x00; + if(ivideo->haveXGIROM) { + v1 = bios[0x74]; + v2 = bios[0x75]; + } + outSISIDXREG(SISSR, 0x07, v1); + outSISIDXREG(SISSR, 0x11, 0x0f); + outSISIDXREG(SISSR, 0x1f, v2); + /* PCI linear mode, RelIO enabled, A0000 decoding disabled */ + outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04); + outSISIDXREG(SISSR, 0x27, 0x74); - if((readb(rom) != 'P') || (readb(rom + 1) != 'C') || - (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) { - iounmap(rom_base); - continue; - } + ptr = cs7b; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x7b]; + } + for(i = 0; i < 3; i++) { + outSISIDXREG(SISSR, 0x31 + i, ptr[i]); + } - pciid = readb(rom + 4) | (readb(rom + 5) << 8); - if(pciid != 0x1039) { - iounmap(rom_base); - continue; - } + if(ivideo->chip == XGI_40) { + if(ivideo->revision_id == 2) { + setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0); + } + outSISIDXREG(SISCR, 0x7d, 0xfe); + outSISIDXREG(SISCR, 0x7e, 0x0f); + } + if(ivideo->revision_id == 0) { /* 40 *and* 20? */ + andSISIDXREG(SISCR, 0x58, 0xd7); + inSISIDXREG(SISCR, 0xcb, reg); + if(reg & 0x20) { + setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */ + } + } - pciid = readb(rom + 6) | (readb(rom + 7) << 8); - if(pciid == ivideo->chip_id) { - memcpy_fromio(myrombase, rom_base, 65536); - iounmap(rom_base); - return myrombase; - } + reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00; + setSISIDXREG(SISCR, 0x38, 0x1f, reg); - iounmap(rom_base); - } + if(ivideo->chip == XGI_20) { + outSISIDXREG(SISSR, 0x36, 0x70); + } else { + outSISIDXREG(SISVID, 0x00, 0x86); + outSISIDXREG(SISVID, 0x32, 0x00); + outSISIDXREG(SISVID, 0x30, 0x00); + outSISIDXREG(SISVID, 0x32, 0x01); + outSISIDXREG(SISVID, 0x30, 0x00); + andSISIDXREG(SISVID, 0x2f, 0xdf); + andSISIDXREG(SISCAP, 0x00, 0x3f); + + outSISIDXREG(SISPART1, 0x2f, 0x01); + outSISIDXREG(SISPART1, 0x00, 0x00); + outSISIDXREG(SISPART1, 0x02, bios[0x7e]); + outSISIDXREG(SISPART1, 0x2e, 0x08); + andSISIDXREG(SISPART1, 0x35, 0x7f); + andSISIDXREG(SISPART1, 0x50, 0xfe); + + inSISIDXREG(SISPART4, 0x00, reg); + if(reg == 1 || reg == 2) { + outSISIDXREG(SISPART2, 0x00, 0x1c); + outSISIDXREG(SISPART4, 0x0d, bios[0x7f]); + outSISIDXREG(SISPART4, 0x0e, bios[0x80]); + outSISIDXREG(SISPART4, 0x10, bios[0x81]); + andSISIDXREG(SISPART4, 0x0f, 0x3f); + + inSISIDXREG(SISPART4, 0x01, reg); + if((reg & 0xf0) >= 0xb0) { + inSISIDXREG(SISPART4, 0x23, reg); + if(reg & 0x20) reg |= 0x40; + outSISIDXREG(SISPART4, 0x23, reg); + reg = (reg & 0x20) ? 0x02 : 0x00; + setSISIDXREG(SISPART1, 0x1e, 0xfd, reg); + } + } -#else + v1 = bios[0x77]; + + inSISIDXREG(SISSR, 0x3b, reg); + if(reg & 0x02) { + inSISIDXREG(SISSR, 0x3a, reg); + v2 = (reg & 0x30) >> 3; + if(!(v2 & 0x04)) v2 ^= 0x02; + inSISIDXREG(SISSR, 0x39, reg); + if(reg & 0x80) v2 |= 0x80; + v2 |= 0x01; + + if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) { + SIS_PCI_PUT_DEVICE(mypdev); + if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4)) + v2 &= 0xf9; + v2 |= 0x08; + v1 &= 0xfe; + } else { + mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL); + if(!mypdev) + mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL); + if(!mypdev) + mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL); + if(mypdev) { + pci_read_config_dword(mypdev, 0x94, ®d); + regd &= 0xfffffeff; + pci_write_config_dword(mypdev, 0x94, regd); + v1 &= 0xfe; + SIS_PCI_PUT_DEVICE(mypdev); + } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) { + v1 &= 0xfe; + } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) || + sisfb_find_host_bridge(ivideo, pdev, 0x1022) || + sisfb_find_host_bridge(ivideo, pdev, 0x700e) || + sisfb_find_host_bridge(ivideo, pdev, 0x10de)) { + if((v2 & 0x06) == 4) + v2 ^= 0x06; + v2 |= 0x08; + } + } + setSISIDXREG(SISCR, 0x5f, 0xf0, v2); + } + outSISIDXREG(SISSR, 0x22, v1); + + if(ivideo->revision_id == 2) { + inSISIDXREG(SISSR, 0x3b, v1); + inSISIDXREG(SISSR, 0x3a, v2); + regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8); + if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) ) + setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01); + + if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) { + /* TODO: set CR5f &0xf1 | 0x01 for version 6570 + * of nforce 2 ROM + */ + if(0) + setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01); + SIS_PCI_PUT_DEVICE(mypdev); + } + } - pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp); - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, - (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE); + v1 = 0x30; + inSISIDXREG(SISSR, 0x3b, reg); + inSISIDXREG(SISCR, 0x5f, v2); + if((!(reg & 0x02)) && (v2 & 0x0e)) + v1 |= 0x08; + outSISIDXREG(SISSR, 0x27, v1); - rom_base = ioremap(ivideo->video_base, 65536); - if(rom_base) { - if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) { - romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8)); - if(romptr <= (0x10000 - 8)) { - rom = rom_base + romptr; - if((readb(rom) == 'P') && (readb(rom + 1) == 'C') && - (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) { - pciid = readb(rom + 4) | (readb(rom + 5) << 8); - if(pciid == 0x1039) { - pciid = readb(rom + 6) | (readb(rom + 7) << 8); - if(pciid == ivideo->chip_id) { - memcpy_fromio(myrombase, rom_base, 65536); - iounmap(rom_base); - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp); - return myrombase; - } - } - } - } - } - iounmap(rom_base); + if(bios[0x64] & 0x01) { + setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]); + } + + v1 = bios[0x4f7]; + pci_read_config_dword(pdev, 0x50, ®d); + regd = (regd >> 20) & 0x0f; + if(regd == 1) { + v1 &= 0xfc; + orSISIDXREG(SISCR, 0x5f, 0x08); + } + outSISIDXREG(SISCR, 0x48, v1); + + setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb); + setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f); + setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f); + setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7); + setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f); + outSISIDXREG(SISCR, 0x70, bios[0x4fc]); + setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f); + outSISIDXREG(SISCR, 0x74, 0xd0); + setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30); + setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f); + setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f); + v1 = bios[0x501]; + if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) { + v1 = 0xf0; + SIS_PCI_PUT_DEVICE(mypdev); + } + outSISIDXREG(SISCR, 0x77, v1); } - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp); -#endif + /* RAM type */ - vfree(myrombase); - return NULL; -} + regb = 0; /* ! */ -#ifdef CONFIG_FB_SIS_300 -static int __devinit -sisfb_chkbuswidth300(struct pci_dev *pdev, SIS_IOTYPE1 *FBAddress) -{ - struct sis_video_info *ivideo = pci_get_drvdata(pdev); - int i, j; - USHORT temp; - UCHAR reg; - - andSISIDXREG(SISSR,0x15,0xFB); - orSISIDXREG(SISSR,0x15,0x04); - outSISIDXREG(SISSR,0x13,0x00); - outSISIDXREG(SISSR,0x14,0xBF); - - for(i=0; i<2; i++) { - temp = 0x1234; - for(j=0; j<4; j++) { - writew(temp, FBAddress); - if(readw(FBAddress) == temp) break; - orSISIDXREG(SISSR,0x3c,0x01); - inSISIDXREG(SISSR,0x05,reg); - inSISIDXREG(SISSR,0x05,reg); - andSISIDXREG(SISSR,0x3c,0xfe); - inSISIDXREG(SISSR,0x05,reg); - inSISIDXREG(SISSR,0x05,reg); - temp++; - } + v1 = 0xff; + if(ivideo->haveXGIROM) { + v1 = bios[0x140 + regb]; } + outSISIDXREG(SISCR, 0x6d, v1); - writel(0x01234567L, FBAddress); - writel(0x456789ABL, (FBAddress+4)); - writel(0x89ABCDEFL, (FBAddress+8)); - writel(0xCDEF0123L, (FBAddress+12)); - inSISIDXREG(SISSR,0x3b,reg); - if(reg & 0x01) { - if(readl((FBAddress+12)) == 0xCDEF0123L) return(4); /* Channel A 128bit */ + ptr = cs128; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x128]; } - if(readl((FBAddress+4)) == 0x456789ABL) return(2); /* Channel B 64bit */ - return(1); /* 32bit */ -} - -static void __devinit -sisfb_setramsize300(struct pci_dev *pdev) -{ - struct sis_video_info *ivideo = pci_get_drvdata(pdev); - SIS_IOTYPE1 *FBAddr = ivideo->video_vbase; - SIS_IOTYPE1 *Addr; - USHORT sr13, sr14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0; - int PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount; - int RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank; - int PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k; - const USHORT SiS_DRAMType[17][5] = { - {0x0C,0x0A,0x02,0x40,0x39}, - {0x0D,0x0A,0x01,0x40,0x48}, - {0x0C,0x09,0x02,0x20,0x35}, - {0x0D,0x09,0x01,0x20,0x44}, - {0x0C,0x08,0x02,0x10,0x31}, - {0x0D,0x08,0x01,0x10,0x40}, - {0x0C,0x0A,0x01,0x20,0x34}, - {0x0C,0x09,0x01,0x08,0x32}, - {0x0B,0x08,0x02,0x08,0x21}, - {0x0C,0x08,0x01,0x08,0x30}, - {0x0A,0x08,0x02,0x04,0x11}, - {0x0B,0x0A,0x01,0x10,0x28}, - {0x09,0x08,0x02,0x02,0x01}, - {0x0B,0x09,0x01,0x08,0x24}, - {0x0B,0x08,0x01,0x04,0x20}, - {0x0A,0x08,0x01,0x02,0x10}, - {0x09,0x08,0x01,0x01,0x00} - }; - - buswidth = sisfb_chkbuswidth300(pdev, FBAddr); - - MB2Bank = 16; - Done = 0; - for(i = 6; i >= 0; i--) { - if(Done) break; - PseudoRankCapacity = 1 << i; - for(j = 4; j >= 1; j--) { - if(Done) break; - PseudoTotalCapacity = PseudoRankCapacity * j; - PseudoAdrPinCount = 15 - j; - if(PseudoTotalCapacity <= 64) { - for(k = 0; k <= 16; k++) { - if(Done) break; - RankCapacity = buswidth * SiS_DRAMType[k][3]; - AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0]; - if(RankCapacity == PseudoRankCapacity) - if(AdrPinCount <= PseudoAdrPinCount) { - if(j == 3) { /* Rank No */ - BankNumHigh = RankCapacity * MB2Bank * 3 - 1; - BankNumMid = RankCapacity * MB2Bank * 1 - 1; - } else { - BankNumHigh = RankCapacity * MB2Bank * j - 1; - BankNumMid = RankCapacity * MB2Bank * j / 2 - 1; - } - PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4; - PhysicalAdrHigh = BankNumHigh; - PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity; - PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh; - /* Write data */ - andSISIDXREG(SISSR,0x15,0xFB); /* Test */ - orSISIDXREG(SISSR,0x15,0x04); /* Test */ - TotalCapacity = SiS_DRAMType[k][3] * buswidth; - sr13 = SiS_DRAMType[k][4]; - if(buswidth == 4) sr14 = (TotalCapacity - 1) | 0x80; - if(buswidth == 2) sr14 = (TotalCapacity - 1) | 0x40; - if(buswidth == 1) sr14 = (TotalCapacity - 1) | 0x00; - outSISIDXREG(SISSR,0x13,sr13); - outSISIDXREG(SISSR,0x14,sr14); - Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh; - /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */ - writew(((USHORT)PhysicalAdrHigh), Addr); - Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh; - /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */ - writew(((USHORT)BankNumMid), Addr); - Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage; - /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */ - writew(((USHORT)PhysicalAdrHalfPage), Addr); - Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage; - /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */ - writew(((USHORT)PhysicalAdrOtherPage), Addr); - /* Read data */ - Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh; - data = readw(Addr); /* *((USHORT *)(Addr)); */ - if(data == PhysicalAdrHigh) Done = 1; - } /* if */ - } /* for k */ - } /* if */ - } /* for j */ - } /* for i */ -} - -static void __devinit sisfb_post_sis300(struct pci_dev *pdev) -{ - struct sis_video_info *ivideo = pci_get_drvdata(pdev); - u8 reg, v1, v2, v3, v4, v5, v6, v7, v8; - u16 index, rindex, memtype = 0; - - outSISIDXREG(SISSR,0x05,0x86); - - if(ivideo->sishw_ext.UseROM) { - if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) { - memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52]; - } else { - inSISIDXREG(SISSR,0x3a,memtype); - } - memtype &= 0x07; + for(i = 0, j = 0; i < 3; i++, j += 8) { + outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]); } - if(ivideo->revision_id <= 0x13) { - v1 = 0x44; v2 = 0x42; v3 = 0x80; - v4 = 0x44; v5 = 0x42; v6 = 0x80; - } else { - v1 = 0x68; v2 = 0x43; v3 = 0x80; /* Assume 125Mhz MCLK */ - v4 = 0x68; v5 = 0x43; v6 = 0x80; /* Assume 125Mhz ECLK */ - if(ivideo->sishw_ext.UseROM) { - index = memtype * 5; - rindex = index + 0x54; - v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - rindex = index + 0x7c; - v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - } + ptr = cs31a; + ptr2 = cs33a; + if(ivideo->haveXGIROM) { + index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6; + ptr = (const u8 *)&bios[index]; + ptr2 = (const u8 *)&bios[index + 0x20]; } - outSISIDXREG(SISSR,0x28,v1); - outSISIDXREG(SISSR,0x29,v2); - outSISIDXREG(SISSR,0x2a,v3); - outSISIDXREG(SISSR,0x2e,v4); - outSISIDXREG(SISSR,0x2f,v5); - outSISIDXREG(SISSR,0x30,v6); - v1 = 0x10; - if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4]; - outSISIDXREG(SISSR,0x07,v1); /* DAC speed */ - outSISIDXREG(SISSR,0x11,0x0f); /* DDC, power save */ - v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a; - v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00; - if(ivideo->sishw_ext.UseROM) { - memtype += 0xa5; - v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8]; - v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16]; - v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24]; - v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32]; - v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40]; - v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48]; - v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56]; - } - if(ivideo->revision_id >= 0x80) v3 &= 0xfd; - outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */ - outSISIDXREG(SISSR,0x16,v2); - outSISIDXREG(SISSR,0x17,v3); - outSISIDXREG(SISSR,0x18,v4); - outSISIDXREG(SISSR,0x19,v5); - outSISIDXREG(SISSR,0x1a,v6); - outSISIDXREG(SISSR,0x1b,v7); - outSISIDXREG(SISSR,0x1c,v8); /* ---- */ - andSISIDXREG(SISSR,0x15,0xfb); - orSISIDXREG(SISSR,0x15,0x04); - if(ivideo->sishw_ext.UseROM) { - if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) { - orSISIDXREG(SISSR,0x19,0x20); - } + for(i = 0; i < 2; i++) { + if(i == 0) { + regd = le32_to_cpu(((u32 *)ptr)[regb]); + rega = 0x6b; + } else { + regd = le32_to_cpu(((u32 *)ptr2)[regb]); + rega = 0x6e; + } + reg = 0x00; + for(j = 0; j < 16; j++) { + reg &= 0xf3; + if(regd & 0x01) reg |= 0x04; + if(regd & 0x02) reg |= 0x08; + regd >>= 2; + outSISIDXREG(SISCR, rega, reg); + inSISIDXREG(SISCR, rega, reg); + inSISIDXREG(SISCR, rega, reg); + reg += 0x10; + } } - v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */ - if(ivideo->revision_id >= 0x80) v1 |= 0x01; - outSISIDXREG(SISSR,0x1f,v1); - outSISIDXREG(SISSR,0x20,0xa0); /* linear & relocated io */ - v1 = 0xf6; v2 = 0x0d; v3 = 0x00; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9]; - v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea]; - } - outSISIDXREG(SISSR,0x23,v1); - outSISIDXREG(SISSR,0x24,v2); - outSISIDXREG(SISSR,0x25,v3); - outSISIDXREG(SISSR,0x21,0x84); - outSISIDXREG(SISSR,0x22,0x00); - outSISIDXREG(SISCR,0x37,0x00); - orSISIDXREG(SISPART1,0x24,0x01); /* unlock crt2 */ - outSISIDXREG(SISPART1,0x00,0x00); - v1 = 0x40; v2 = 0x11; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb]; + + andSISIDXREG(SISCR, 0x6e, 0xfc); + + ptr = NULL; + if(ivideo->haveXGIROM) { + index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6; + ptr = (const u8 *)&bios[index]; } - outSISIDXREG(SISPART1,0x02,v1); - if(ivideo->revision_id >= 0x80) v2 &= ~0x01; - inSISIDXREG(SISPART4,0x00,reg); - if((reg == 1) || (reg == 2)) { - outSISIDXREG(SISCR,0x37,0x02); - outSISIDXREG(SISPART2,0x00,0x1c); - v4 = 0x00; v5 = 0x00; v6 = 0x10; - if(ivideo->sishw_ext.UseROM) { - v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5]; - v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6]; - v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7]; - } - outSISIDXREG(SISPART4,0x0d,v4); - outSISIDXREG(SISPART4,0x0e,v5); - outSISIDXREG(SISPART4,0x10,v6); - outSISIDXREG(SISPART4,0x0f,0x3f); - inSISIDXREG(SISPART4,0x01,reg); - if(reg >= 0xb0) { - inSISIDXREG(SISPART4,0x23,reg); - reg &= 0x20; - reg <<= 1; - outSISIDXREG(SISPART4,0x23,reg); - } - } else { - v2 &= ~0x10; + for(i = 0; i < 4; i++) { + setSISIDXREG(SISCR, 0x6e, 0xfc, i); + reg = 0x00; + for(j = 0; j < 2; j++) { + regd = 0; + if(ptr) { + regd = le32_to_cpu(((u32 *)ptr)[regb * 8]); + ptr += 4; + } + /* reg = 0x00; */ + for(k = 0; k < 16; k++) { + reg &= 0xfc; + if(regd & 0x01) reg |= 0x01; + if(regd & 0x02) reg |= 0x02; + regd >>= 2; + outSISIDXREG(SISCR, 0x6f, reg); + inSISIDXREG(SISCR, 0x6f, reg); + inSISIDXREG(SISCR, 0x6f, reg); + reg += 0x08; + } + } } - outSISIDXREG(SISSR,0x32,v2); - andSISIDXREG(SISPART1,0x24,0xfe); /* Lock CRT2 */ - inSISIDXREG(SISSR,0x16,reg); - reg &= 0xc3; - outSISIDXREG(SISCR,0x35,reg); - outSISIDXREG(SISCR,0x83,0x00); -#if !defined(__i386__) && !defined(__x86_64__) - if(sisfb_videoram) { - outSISIDXREG(SISSR,0x13,0x28); /* ? */ - reg = ((sisfb_videoram >> 10) - 1) | 0x40; - outSISIDXREG(SISSR,0x14,reg); - } else { -#endif - /* Need to map max FB size for finding out about RAM size */ - ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000); - if(ivideo->video_vbase) { - sisfb_setramsize300(pdev); - iounmap(ivideo->video_vbase); - } else { - printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n"); - outSISIDXREG(SISSR,0x13,0x28); /* ? */ - outSISIDXREG(SISSR,0x14,0x47); /* 8MB, 64bit default */ - } -#if !defined(__i386__) && !defined(__x86_64__) + + ptr = cs148; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x148]; } -#endif - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7]; - } else { - inSISIDXREG(SISSR,0x3a,reg); - if((reg & 0x30) == 0x30) { - v1 = 0x04; /* PCI */ - v2 = 0x92; - } else { - v1 = 0x14; /* AGP */ - v2 = 0xb2; - } + for(i = 0, j = 0; i < 2; i++, j += 8) { + outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]); } - outSISIDXREG(SISSR,0x21,v1); - outSISIDXREG(SISSR,0x22,v2); -} -#endif - -#ifdef CONFIG_FB_SIS_315 -static void __devinit sisfb_post_sis315330(struct pci_dev *pdev) -{ -#ifdef YET_TO_BE_DONE - struct sis_video_info *ivideo = pci_get_drvdata(pdev); - u8 reg, v1, v2, v3, v4, v5, v6, v7, v8; - u16 index, rindex, memtype = 0; - u32 reg1_32, reg2_32, reg3_32; - int i; - /* Unlock */ - /* outSISIDXREG(0x3c4,0x05,0x86); */ - outSISIDXREG(SISSR,0x05,0x86); + andSISIDXREG(SISCR, 0x89, 0x8f); - /* Enable relocated i/o ports */ - /* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */ - setSISIDXREG(SISSR,0x20,~0x10,0x20); + ptr = cs45a; + if(ivideo->haveXGIROM) { + index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6; + ptr = (const u8 *)&bios[index]; + } + regd = le16_to_cpu(((const u16 *)ptr)[regb]); + reg = 0x80; + for(i = 0; i < 5; i++) { + reg &= 0xfc; + if(regd & 0x01) reg |= 0x01; + if(regd & 0x02) reg |= 0x02; + regd >>= 2; + outSISIDXREG(SISCR, 0x89, reg); + inSISIDXREG(SISCR, 0x89, reg); + inSISIDXREG(SISCR, 0x89, reg); + reg += 0x10; + } - /* Clear regs */ - for(i = 0; i < 0x22; i++) { - outSISIDXREG(SISSR,(0x06 + i),0x00); + v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13; + if(ivideo->haveXGIROM) { + v1 = bios[0x118 + regb]; + v2 = bios[0xf8 + regb]; + v3 = bios[0x120 + regb]; + v4 = bios[0x1ca]; } - v1 = 0x0d; - if( is 330) v1 = 0x0b; - for(i = 0; i < v1; i++) { - outSISIDXREG(SISSR,(0x31 + i),0x00); + outSISIDXREG(SISCR, 0x45, v1 & 0x0f); + outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07); + orSISIDXREG(SISCR, 0x40, v1 & 0x80); + outSISIDXREG(SISCR, 0x41, v2); + + ptr = cs170; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x170]; } - for(i = 0; i < 0x10; i++) { - outSISIDXREG(SISCR,(0x30 + i),0x00); - } - - /* Reset clocks */ - reg = inSISREG(SISMISCR); - outSISIDXREG(SISSR,0x28,0x81); - outSISIDXREG(SISSR,0x2A,0x00); - outSISIDXREG(SISSR,0x29,0xE1); - outSISREG(SISMISCW,(reg | 0x0c)); - outSISIDXREG(SISSR,0x2B,0x81); - outSISIDXREG(SISSR,0x2D,0x00); - outSISIDXREG(SISSR,0x2C,0xE1); - outSISIDXREG(SISSR,0x2E,0x81); - outSISIDXREG(SISSR,0x30,0x00); - outSISIDXREG(SISSR,0x2F,0xE1); - SiS_DDC2Delay(....); - outSISREG(SISMISCW,reg); - - /* Get memory type */ - if(ivideo->sishw_ext.UseROM) { - if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) { - memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52]; - } else { - inSISIDXREG(SISSR,0x3a,memtype); - } - memtype &= 0x03; - if( is 330 ) { - if(memtype <= 1) memtype = 0; - else { - inSISIDXREG(SISCR,0x5F,reg); - reg &= 0x30; - switch(reg) { - case 0x00: memtype = 1; break; - case 0x10: memtype = 3; break; - case 0x20: memtype = 3; break; - default: memtype = 2; - } - } - } + for(i = 0, j = 0; i < 7; i++, j += 8) { + outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]); } - /* Set clocks */ - v1 = 0x3b; v2 = 0x22; v3 = 0x01; /* Assume 143Mhz MCLK */ - v4 = 0x5c; v5 = 0x23; v6 = 0x01; /* Assume 166Mhz ECLK */ - if(ivideo->sishw_ext.UseROM) { - index = memtype * 5; - rindex = index + 0x54; - v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - rindex = index + 0x68; - v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++]; - } - outSISIDXREG(SISSR,0x28,v1); - outSISIDXREG(SISSR,0x29,v2); - outSISIDXREG(SISSR,0x2a,v3); - if( is 330 ) { - inSISIDXREG(SISSR,0x3a,reg); - reg &= 0x03; - if(reg >= 2) { - ... - } + outSISIDXREG(SISCR, 0x59, v3); + + ptr = cs1a8; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x1a8]; + } + for(i = 0, j = 0; i < 3; i++, j += 8) { + outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]); } - outSISIDXREG(SISSR,0x2e,v4); - outSISIDXREG(SISSR,0x2f,v5); - outSISIDXREG(SISSR,0x30,v6); - - /* End of comp with 330 */ - - v1 = 0x18; - if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c]; - outSISIDXREG(SISSR,0x07,v1); - outSISIDXREG(SISSR,0x11,0x0f); - - v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9; - v5 = 0xa0; v6 = 0x00; v7 = 0x30; - if(ivideo->sishw_ext.UseROM) { - index = memtype + 0x7d; - v1 = ivideo->sishw_ext.pjVirtualRomBase[index]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4]; - v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8]; - v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12]; - v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16]; - v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20]; - v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24]; - } - outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0x7d step 4) */ - outSISIDXREG(SISSR,0x16,v2); - outSISIDXREG(SISSR,0x17,v3); - outSISIDXREG(SISSR,0x18,v4); - outSISIDXREG(SISSR,0x19,v5); - outSISIDXREG(SISSR,0x1a,v6); - outSISIDXREG(SISSR,0x1b,v7); - outSISIDXREG(SISSR,0x1c,v8); /* ---- */ - - v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00; - if(ivideo->sishw_ext.UseROM) { - index = memtype + 0xa2; - v1 = ivideo->sishw_ext.pjVirtualRomBase[index]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4]; - v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8]; - v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12]; - v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16]; - } - outSISIDXREG(SISCR,0x40,v1); - outSISIDXREG(SISCR,0x41,v2); - outSISIDXREG(SISCR,0x42,v3); - outSISIDXREG(SISCR,0x43,v4); - outSISIDXREG(SISCR,0x44,v5); - - if( is 330 ) { - - v1 = 0x; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA]; - } - outSISIDXREG(SISCR,0x59,v1); - - v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x; - v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x; - if(ivideo->sishw_ext.UseROM) { - index = memtype + 0xbe; - v1 = ivideo->sishw_ext.pjVirtualRomBase[index]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4]; - v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8]; - v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12]; - v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16]; - v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20]; - v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24]; - v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28]; - } - outSISIDXREG(SISCR,0x68,v1); - outSISIDXREG(SISCR,0x69,v2); - outSISIDXREG(SISCR,0x6a,v3); - outSISIDXREG(SISCR,0x6b,v4); - outSISIDXREG(SISCR,0x6c,v5); - outSISIDXREG(SISCR,0x6d,v6); - outSISIDXREG(SISCR,0x6e,v7); - outSISIDXREG(SISCR,0x6f,v8); - - v1 = 0x20; - inSISIDXREG(SISSR,0x3b,reg); - - if(!(reg & 0x04)) { - inSISIDXREG(SISCR,0x5F,reg); - reg &= 0x30; - if(reg) v1 = 0x23; - } - outSISIDXREG(SISCR,0x48,v1); - outSISIDXREG(SISCR,0x4c,0x20); - - xx= xxx(); - if(xx >= 1) { - v1 = 0x; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA]; - } - outSISIDXREG(SISCR,0x59,v1); - } + ptr = cs100; + if(ivideo->haveXGIROM) { + ptr = (const u8 *)&bios[0x100]; + } + for(i = 0, j = 0; i < 2; i++, j += 8) { + outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]); + } + outSISIDXREG(SISCR, 0xcf, v4); - } else { + outSISIDXREG(SISCR, 0x83, 0x09); + outSISIDXREG(SISCR, 0x87, 0x00); - outSISIDXREG(SISCR,0x48,0x23); + if(ivideo->chip == XGI_40) { + if( (ivideo->revision_id == 1) || + (ivideo->revision_id == 2) ) { + outSISIDXREG(SISCR, 0x8c, 0x87); + } + } - andSISIDXREG(SISSR,0x16,0x0f); - if(memtype <= 1) { - orSISIDXREG(SISSR,0x16,0x80); - } else { - v1 = 0x0f; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype]; - } - if(!(v1 & 0x10)) v2 = 0xc0; - else v2 = 0xd0; - orSISIDXREG(SISSR,0x16,v2); - andSISIDXREG(SISSR,0x16,0x0f); - if(!(v1 & 0x10)) v2 = 0x80; - else v2 = 0xA0; - orSISIDXREG(SISSR,0x16,v2); - } - - if(memtype >= 2) { - const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 }; - const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 }; - for(i = 0; i < 11; i++) { - outSISIDXREG(SISSR,0x3c,sr3cseq1[i]); - } - outSISIDXREG(SISSR,0x3d,0x00); - outSISIDXREG(SISSR,0x3d,0x04); - SiS_DDC2Delay(0x200); - v1 = inSISIDXREG(SISCR,0xEC); - v2 = inSISIDXREG(SISCR,0xED); - reg1_32 = (v2 << 8) | v1; - outSISIDXREG(SISSR,0x3D,0x00); - for(i = 0; i < 11; i++) { - outSISIDXREG(SISSR,0x3c,sr3cseq2[i]); - } - outSISIDXREG(SISSR,0x3d,0x00); - outSISIDXREG(SISSR,0x3d,0x04); - SiS_DDC2Delay(0x200); - v1 = inSISIDXREG(SISCR,0xEC); - v2 = inSISIDXREG(SISCR,0xED); - reg2_32 = (v2 << 8) | v1; - outSISIDXREG(SISSR,0x3D,0x00); - reg3_32 = reg2_32 << 1; - reg2_32 >>= 1; - reg3_32 += reg2_32; - v1 = 0x40; - if(reg3_32 > reg1_32) v1 = 0x10; - outSISIDXREG(SISCR,0x59,v1); - } + outSISIDXREG(SISSR, 0x17, 0x00); + outSISIDXREG(SISSR, 0x1a, 0x87); + if(ivideo->chip == XGI_20) { + outSISIDXREG(SISSR, 0x15, 0x00); + outSISIDXREG(SISSR, 0x1c, 0x00); } - v1 = 0x00; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99]; + ramtype = 0x00; v1 = 0x10; + if(ivideo->haveXGIROM) { + ramtype = bios[0x62]; + v1 = bios[0x1d2]; + } + if(!(ramtype & 0x80)) { + if(ivideo->chip == XGI_20) { + outSISIDXREG(SISCR, 0x97, v1); + inSISIDXREG(SISCR, 0x97, reg); + if(reg & 0x10) { + ramtype = (reg & 0x01) << 1; + } + } else { + inSISIDXREG(SISSR, 0x39, reg); + ramtype = reg & 0x02; + if(!(ramtype)) { + inSISIDXREG(SISSR, 0x3a, reg); + ramtype = (reg >> 1) & 0x01; + } + } } - outSISIDXREG(SISSR,0x1f,v1); + ramtype &= 0x07; + + regb = 0; /* ! */ + + switch(ramtype) { + case 0: + sisfb_post_xgi_setclocks(ivideo, regb); + if((ivideo->chip == XGI_20) || + (ivideo->revision_id == 1) || + (ivideo->revision_id == 2)) { + v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb]; + if(ivideo->haveXGIROM) { + v1 = bios[regb + 0x158]; + v2 = bios[regb + 0x160]; + v3 = bios[regb + 0x168]; + } + outSISIDXREG(SISCR, 0x82, v1); + outSISIDXREG(SISCR, 0x85, v2); + outSISIDXREG(SISCR, 0x86, v3); + } else { + outSISIDXREG(SISCR, 0x82, 0x88); + outSISIDXREG(SISCR, 0x86, 0x00); + inSISIDXREG(SISCR, 0x86, reg); + outSISIDXREG(SISCR, 0x86, 0x88); + inSISIDXREG(SISCR, 0x86, reg); + outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]); + outSISIDXREG(SISCR, 0x82, 0x77); + outSISIDXREG(SISCR, 0x85, 0x00); + inSISIDXREG(SISCR, 0x85, reg); + outSISIDXREG(SISCR, 0x85, 0x88); + inSISIDXREG(SISCR, 0x85, reg); + outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]); + outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]); + } + if(ivideo->chip == XGI_40) { + outSISIDXREG(SISCR, 0x97, 0x00); + } + outSISIDXREG(SISCR, 0x98, 0x01); + outSISIDXREG(SISCR, 0x9a, 0x02); - outSISIDXREG(SISSR,0x20,0x20); + outSISIDXREG(SISSR, 0x18, 0x01); + if((ivideo->chip == XGI_20) || + (ivideo->revision_id == 2)) { + outSISIDXREG(SISSR, 0x19, 0x40); + } else { + outSISIDXREG(SISSR, 0x19, 0x20); + } + outSISIDXREG(SISSR, 0x16, 0x00); + outSISIDXREG(SISSR, 0x16, 0x80); + if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) { + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + outSISIDXREG(SISSR, 0x18, 0x00); + if((ivideo->chip == XGI_20) || + (ivideo->revision_id == 2)) { + outSISIDXREG(SISSR, 0x19, 0x40); + } else { + outSISIDXREG(SISSR, 0x19, 0x20); + } + } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) { + /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */ + } + outSISIDXREG(SISSR, 0x16, 0x00); + outSISIDXREG(SISSR, 0x16, 0x80); + sisfb_post_xgi_delay(ivideo, 4); + v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83; + if(ivideo->haveXGIROM) { + v1 = bios[0xf0]; + index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e; + v2 = bios[index]; + v3 = bios[index + 1]; + v4 = bios[index + 2]; + v5 = bios[index + 3]; + } + outSISIDXREG(SISSR, 0x18, v1); + outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01)); + outSISIDXREG(SISSR, 0x16, v2); + outSISIDXREG(SISSR, 0x16, v3); + sisfb_post_xgi_delay(ivideo, 0x43); + outSISIDXREG(SISSR, 0x1b, 0x03); + sisfb_post_xgi_delay(ivideo, 0x22); + outSISIDXREG(SISSR, 0x18, v1); + outSISIDXREG(SISSR, 0x19, 0x00); + outSISIDXREG(SISSR, 0x16, v4); + outSISIDXREG(SISSR, 0x16, v5); + outSISIDXREG(SISSR, 0x1b, 0x00); + break; + case 1: + outSISIDXREG(SISCR, 0x82, 0x77); + outSISIDXREG(SISCR, 0x86, 0x00); + inSISIDXREG(SISCR, 0x86, reg); + outSISIDXREG(SISCR, 0x86, 0x88); + inSISIDXREG(SISCR, 0x86, reg); + v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb]; + if(ivideo->haveXGIROM) { + v1 = bios[regb + 0x168]; + v2 = bios[regb + 0x160]; + v3 = bios[regb + 0x158]; + } + outSISIDXREG(SISCR, 0x86, v1); + outSISIDXREG(SISCR, 0x82, 0x77); + outSISIDXREG(SISCR, 0x85, 0x00); + inSISIDXREG(SISCR, 0x85, reg); + outSISIDXREG(SISCR, 0x85, 0x88); + inSISIDXREG(SISCR, 0x85, reg); + outSISIDXREG(SISCR, 0x85, v2); + outSISIDXREG(SISCR, 0x82, v3); + outSISIDXREG(SISCR, 0x98, 0x01); + outSISIDXREG(SISCR, 0x9a, 0x02); + + outSISIDXREG(SISSR, 0x28, 0x64); + outSISIDXREG(SISSR, 0x29, 0x63); + sisfb_post_xgi_delay(ivideo, 15); + outSISIDXREG(SISSR, 0x18, 0x00); + outSISIDXREG(SISSR, 0x19, 0x20); + outSISIDXREG(SISSR, 0x16, 0x00); + outSISIDXREG(SISSR, 0x16, 0x80); + outSISIDXREG(SISSR, 0x18, 0xc5); + outSISIDXREG(SISSR, 0x19, 0x23); + outSISIDXREG(SISSR, 0x16, 0x00); + outSISIDXREG(SISSR, 0x16, 0x80); + sisfb_post_xgi_delay(ivideo, 1); + outSISIDXREG(SISCR, 0x97,0x11); + sisfb_post_xgi_setclocks(ivideo, regb); + sisfb_post_xgi_delay(ivideo, 0x46); + outSISIDXREG(SISSR, 0x18, 0xc5); + outSISIDXREG(SISSR, 0x19, 0x23); + outSISIDXREG(SISSR, 0x16, 0x00); + outSISIDXREG(SISSR, 0x16, 0x80); + sisfb_post_xgi_delay(ivideo, 1); + outSISIDXREG(SISSR, 0x1b, 0x04); + sisfb_post_xgi_delay(ivideo, 1); + outSISIDXREG(SISSR, 0x1b, 0x00); + sisfb_post_xgi_delay(ivideo, 1); + v1 = 0x31; + if(ivideo->haveXGIROM) { + v1 = bios[0xf0]; + } + outSISIDXREG(SISSR, 0x18, v1); + outSISIDXREG(SISSR, 0x19, 0x06); + outSISIDXREG(SISSR, 0x16, 0x04); + outSISIDXREG(SISSR, 0x16, 0x84); + sisfb_post_xgi_delay(ivideo, 1); + break; + default: + sisfb_post_xgi_setclocks(ivideo, regb); + if((ivideo->chip == XGI_40) && + ((ivideo->revision_id == 1) || + (ivideo->revision_id == 2))) { + outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]); + outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]); + outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]); + } else { + outSISIDXREG(SISCR, 0x82, 0x88); + outSISIDXREG(SISCR, 0x86, 0x00); + inSISIDXREG(SISCR, 0x86, reg); + outSISIDXREG(SISCR, 0x86, 0x88); + outSISIDXREG(SISCR, 0x82, 0x77); + outSISIDXREG(SISCR, 0x85, 0x00); + inSISIDXREG(SISCR, 0x85, reg); + outSISIDXREG(SISCR, 0x85, 0x88); + inSISIDXREG(SISCR, 0x85, reg); + v1 = cs160[regb]; v2 = cs158[regb]; + if(ivideo->haveXGIROM) { + v1 = bios[regb + 0x160]; + v2 = bios[regb + 0x158]; + } + outSISIDXREG(SISCR, 0x85, v1); + outSISIDXREG(SISCR, 0x82, v2); + } + if(ivideo->chip == XGI_40) { + outSISIDXREG(SISCR, 0x97, 0x11); + } + if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) { + outSISIDXREG(SISCR, 0x98, 0x01); + } else { + outSISIDXREG(SISCR, 0x98, 0x03); + } + outSISIDXREG(SISCR, 0x9a, 0x02); - v1 = 0xf6; v2 = 0x0d; v3 = 0x33; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d]; - v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e]; + if(ivideo->chip == XGI_40) { + outSISIDXREG(SISSR, 0x18, 0x01); + } else { + outSISIDXREG(SISSR, 0x18, 0x00); + } + outSISIDXREG(SISSR, 0x19, 0x40); + outSISIDXREG(SISSR, 0x16, 0x00); + outSISIDXREG(SISSR, 0x16, 0x80); + if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) { + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + sisfb_post_xgi_delay(ivideo, 0x43); + outSISIDXREG(SISSR, 0x18, 0x00); + outSISIDXREG(SISSR, 0x19, 0x40); + outSISIDXREG(SISSR, 0x16, 0x00); + outSISIDXREG(SISSR, 0x16, 0x80); + } + sisfb_post_xgi_delay(ivideo, 4); + v1 = 0x31; + if(ivideo->haveXGIROM) { + v1 = bios[0xf0]; + } + outSISIDXREG(SISSR, 0x18, v1); + outSISIDXREG(SISSR, 0x19, 0x01); + if(ivideo->chip == XGI_40) { + outSISIDXREG(SISSR, 0x16, bios[0x53e]); + outSISIDXREG(SISSR, 0x16, bios[0x53f]); + } else { + outSISIDXREG(SISSR, 0x16, 0x05); + outSISIDXREG(SISSR, 0x16, 0x85); + } + sisfb_post_xgi_delay(ivideo, 0x43); + if(ivideo->chip == XGI_40) { + outSISIDXREG(SISSR, 0x1b, 0x01); + } else { + outSISIDXREG(SISSR, 0x1b, 0x03); + } + sisfb_post_xgi_delay(ivideo, 0x22); + outSISIDXREG(SISSR, 0x18, v1); + outSISIDXREG(SISSR, 0x19, 0x00); + if(ivideo->chip == XGI_40) { + outSISIDXREG(SISSR, 0x16, bios[0x540]); + outSISIDXREG(SISSR, 0x16, bios[0x541]); + } else { + outSISIDXREG(SISSR, 0x16, 0x05); + outSISIDXREG(SISSR, 0x16, 0x85); + } + outSISIDXREG(SISSR, 0x1b, 0x00); } - outSISIDXREG(SISSR,0x23,v1); - outSISIDXREG(SISSR,0x24,v2); - outSISIDXREG(SISSR,0x25,v3); - outSISIDXREG(SISSR,0x21,0x84); - outSISIDXREG(SISSR,0x22,0x00); - outSISIDXREG(SISSR,0x27,0x1f); - - v1 = 0x00; v2 = 0x00; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1]; - } - outSISIDXREG(SISSR,0x31,v1); - outSISIDXREG(SISSR,0x33,v2); - - v1 = 0x11; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0]; - } - v2 = inSISIDXREG(SISPART4,0x00); - if((v2 != 1) && (v2 != 2)) v1 &= 0xef; - outSISIDXREG(SISSR,0x32,v1); - - /* AGP */ - pci_read_config_long(pdev, 0x50, ®1_32); - reg1_32 >>= 20; - reg1_32 &= 0x0f; - if(reg1_32 == 1) { - v1 = 0xAA; v2 = 0x33; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E]; - } - } else { - v1 = 0x88; v2 = 0x03; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6]; - } + regb = 0; /* ! */ + v1 = 0x03; + if(ivideo->haveXGIROM) { + v1 = bios[0x110 + regb]; } - outSISIDXREG(SISCR,0x49,v1); - outSISIDXREG(SISSR,0x25,v2); + outSISIDXREG(SISSR, 0x1b, v1); - v1 = inSISIDXREG(SISPART4,0x00); - if((v1 == 1) || (v1 == 2)) { - orSISIDXREG(SISPART1,0x2F,0x01); /* Unlock CRT2 */ - outSISIDXREG(SISPART1,0x00,0x00); - v1 = 0x00; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6]; - } - outSISIDXREG(SISPART1,0x02,v1); - outSISIDXREG(SISPART1,0x2E,0x08); - outSISIDXREG(SISPART2,0x00,0x1c); - v1 = 0x40; v2 = 0x00; v3 = 0x80; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8]; - v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb]; - } - outSISIDXREG(SISPART4,0x0d,v1); - outSISIDXREG(SISPART4,0x0e,v2); - outSISIDXREG(SISPART4,0x10,v3); - outSISIDXREG(SISPART4,0x0F,0x3F); - - inSISIDXREG(SISPART4,0x01,reg); - if(reg >= 0xb0) { - inSISIDXREG(SISPART4,0x23,reg); - reg &= 0x20; - reg <<= 1; - outSISIDXREG(SISPART4,0x23,reg); - } + /* RAM size */ + v1 = 0x00; v2 = 0x00; + if(ivideo->haveXGIROM) { + v1 = bios[0x62]; + v2 = bios[0x63]; } - outSISIDXREG(SISCR,0x37,0x02); /* Why? */ - - outSISIDXREG(SISCR,0x83,0x00); - outSISIDXREG(SISCR,0x90,0x00); - andSISIDXREG(SISSR,0x5B,0xDF); - outSISIDXREG(SISVID,0x00,0x86); - outSISIDXREG(SISVID,0x32,0x00); - outSISIDXREG(SISVID,0x30,0x00); - outSISIDXREG(SISVID,0x32,0x01); - outSISIDXREG(SISVID,0x30,0x00); - orSISIDXREG(SISCR,0x63,0x80); - /* End of Init1 */ - - /* Set Mode 0x2e */ - - /* Ramsize */ - orSISIDXREG(SISSR,0x16,0x0f); - orSISIDXREG(SISSR,0x18,0xA9); - orSISIDXREG(SISSR,0x19,0xA0); - orSISIDXREG(SISSR,0x1B,0x30); - andSISIDXREG(SISSR,0x17,0xF8); - orSISIDXREG(SISSR,0x19,0x03); - andSIDIDXREG(SISSR,0x13,0x00); + regb = 0; /* ! */ + regd = 1 << regb; + if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) { - /* Need to map max FB size for finding out about RAM size */ - ivideo->video_vbase = ioremap(ivideo->video_base, 0x4000000); - if(ivideo->video_vbase) { - /* Find out about bus width */ - if(memtype <= 1) { - outSISIDXREG(SISSR,0x14,0x02); - andSISIDXREG(SISSR,0x16,0x0F); - orSISIDXREG(SISSR,0x16,0x80); + outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]); + outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]); - ... + } else { - } else { + /* Set default mode, don't clear screen */ + ivideo->SiS_Pr.SiS_UseOEM = FALSE; + SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE); + SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE); + ivideo->curFSTN = ivideo->curDSTN = 0; + ivideo->SiS_Pr.VideoMemorySize = 8 << 20; + SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80); - ... + outSISIDXREG(SISSR, 0x05, 0x86); - } + /* Disable read-cache */ + andSISIDXREG(SISSR, 0x21, 0xdf); + sisfb_post_xgi_ramsize(ivideo); + /* Enable read-cache */ + orSISIDXREG(SISSR, 0x21, 0x20); - /* Find out about size */ + } +#if 0 + printk(KERN_DEBUG "-----------------\n"); + for(i = 0; i < 0xff; i++) { + inSISIDXREG(SISCR, i, reg); + printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg); + } + for(i = 0; i < 0x40; i++) { + inSISIDXREG(SISSR, i, reg); + printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg); + } + printk(KERN_DEBUG "-----------------\n"); +#endif - iounmap(ivideo->video_vbase); + /* Sense CRT1 */ + if(ivideo->chip == XGI_20) { + orSISIDXREG(SISCR, 0x32, 0x20); } else { - printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n"); - outSISIDXREG(SISSR,0x14,0x??); /* 8MB, 64bit default */ + inSISIDXREG(SISPART4, 0x00, reg); + if((reg == 1) || (reg == 2)) { + sisfb_sense_crt1(ivideo); + } else { + orSISIDXREG(SISCR, 0x32, 0x20); + } } - /* AGP (Missing: Checks for VIA and AMD hosts) */ - v1 = 0xA5; v2 = 0xFB; - if(ivideo->sishw_ext.UseROM) { - v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A]; - v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B]; + /* Set default mode, don't clear screen */ + ivideo->SiS_Pr.SiS_UseOEM = FALSE; + SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE); + SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE); + ivideo->curFSTN = ivideo->curDSTN = 0; + SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80); + + outSISIDXREG(SISSR, 0x05, 0x86); + + /* Display off */ + orSISIDXREG(SISSR, 0x01, 0x20); + + /* Save mode number in CR34 */ + outSISIDXREG(SISCR, 0x34, 0x2e); + + /* Let everyone know what the current mode is */ + ivideo->modeprechange = 0x2e; + + if(ivideo->chip == XGI_40) { + inSISIDXREG(SISCR, 0xca, reg); + inSISIDXREG(SISCR, 0xcc, v1); + if((reg & 0x10) && (!(v1 & 0x04))) { + printk(KERN_ERR + "sisfb: Please connect power to the card.\n"); + return 0; + } } - outSISIDXREG(SISSR,0x21,v1); - outSISIDXREG(SISSR,0x22,v2); -#endif - return; + return 1; } #endif - -static int __devinit sisfb_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int __devinit +sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data]; - struct sis_video_info *ivideo = NULL; - struct fb_info *sis_fb_info = NULL; + struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data]; + struct sis_video_info *ivideo = NULL; + struct fb_info *sis_fb_info = NULL; u16 reg16; u8 reg; - int sisvga_enabled = 0, i; + int i, ret; - if(sisfb_off) return -ENXIO; + if(sisfb_off) + return -ENXIO; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3)) sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev); - if(!sis_fb_info) return -ENOMEM; + if(!sis_fb_info) + return -ENOMEM; #else sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL); - if(!sis_fb_info) return -ENOMEM; + if(!sis_fb_info) + return -ENOMEM; memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo)); sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info)); #endif @@ -4787,27 +5890,34 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, ivideo = (struct sis_video_info *)sis_fb_info->par; ivideo->memyselfandi = sis_fb_info; + ivideo->sisfb_id = SISFB_ID; + if(card_list == NULL) { - ivideo->cardnumber = 0; + ivideo->cardnumber = 0; } else { - struct sis_video_info *countvideo = card_list; - ivideo->cardnumber = 1; - while((countvideo = countvideo->next) != NULL) ivideo->cardnumber++; + struct sis_video_info *countvideo = card_list; + ivideo->cardnumber = 1; + while((countvideo = countvideo->next) != 0) + ivideo->cardnumber++; } strncpy(ivideo->myid, chipinfo->chip_name, 30); ivideo->warncount = 0; ivideo->chip_id = pdev->device; + ivideo->chip_vendor = pdev->vendor; pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id); - ivideo->sishw_ext.jChipRevision = ivideo->revision_id; + ivideo->SiS_Pr.ChipRevision = ivideo->revision_id; pci_read_config_word(pdev, PCI_COMMAND, ®16); - sisvga_enabled = reg16 & 0x01; + ivideo->sisvga_enabled = reg16 & 0x01; ivideo->pcibus = pdev->bus->number; ivideo->pcislot = PCI_SLOT(pdev->devfn); ivideo->pcifunc = PCI_FUNC(pdev->devfn); ivideo->subsysvendor = pdev->subsystem_vendor; ivideo->subsysdevice = pdev->subsystem_device; +#ifdef SIS_OLD_CONFIG_COMPAT + ivideo->ioctl32registered = 0; +#endif #ifndef MODULE if(sisfb_mode_idx == -1) { @@ -4827,6 +5937,24 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, ivideo->sisfb_thismonitor.datavalid = FALSE; + ivideo->current_base = 0; + + ivideo->engineok = 0; + + ivideo->sisfb_was_boot_device = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) + if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) { + if(ivideo->sisvga_enabled) + ivideo->sisfb_was_boot_device = 1; + else { + printk(KERN_DEBUG "sisfb: PCI device is disabled, " + "but marked as boot video device ???\n"); + printk(KERN_DEBUG "sisfb: I will not accept this " + "as the primary VGA device\n"); + } + } +#endif + ivideo->sisfb_parm_mem = sisfb_parm_mem; ivideo->sisfb_accel = sisfb_accel; ivideo->sisfb_ypan = sisfb_ypan; @@ -4846,7 +5974,6 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, ivideo->sisfb_tvstd = sisfb_tvstd; ivideo->tvxpos = sisfb_tvxposoffset; ivideo->tvypos = sisfb_tvyposoffset; - ivideo->sisfb_filter = sisfb_filter; ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate; #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) ivideo->sisfb_inverse = sisfb_inverse; @@ -4854,7 +5981,7 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, ivideo->refresh_rate = 0; if(ivideo->sisfb_parm_rate != -1) { - ivideo->refresh_rate = ivideo->sisfb_parm_rate; + ivideo->refresh_rate = ivideo->sisfb_parm_rate; } ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd; @@ -4863,8 +5990,8 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl; ivideo->SiS_Pr.SiS_Backup70xx = 0xff; - ivideo->SiS_Pr.SiS_CHOverScan = -1; - ivideo->SiS_Pr.SiS_ChSW = FALSE; + ivideo->SiS_Pr.SiS_CHOverScan = -1; + ivideo->SiS_Pr.SiS_ChSW = FALSE; ivideo->SiS_Pr.SiS_UseLCDA = FALSE; ivideo->SiS_Pr.HaveEMI = FALSE; ivideo->SiS_Pr.HaveEMILCD = FALSE; @@ -4873,12 +6000,13 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, ivideo->SiS_Pr.SiS_MyCR63 = 0x63; ivideo->SiS_Pr.PDC = -1; ivideo->SiS_Pr.PDCA = -1; + ivideo->SiS_Pr.DDCPortMixup = FALSE; #ifdef CONFIG_FB_SIS_315 if(ivideo->chip >= SIS_330) { - ivideo->SiS_Pr.SiS_MyCR63 = 0x53; - if(ivideo->chip >= SIS_661) { - ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE; - } + ivideo->SiS_Pr.SiS_MyCR63 = 0x53; + if(ivideo->chip >= SIS_661) { + ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE; + } } #endif @@ -4891,9 +6019,9 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, switch(ivideo->nbridge->device) { #ifdef CONFIG_FB_SIS_300 case PCI_DEVICE_ID_SI_730: - ivideo->chip = SIS_730; + ivideo->chip = SIS_730; strcpy(ivideo->myid, "SiS 730"); - break; + break; #endif #ifdef CONFIG_FB_SIS_315 case PCI_DEVICE_ID_SI_651: @@ -4901,22 +6029,28 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, strcpy(ivideo->myid, "SiS 651"); break; case PCI_DEVICE_ID_SI_740: - ivideo->chip = SIS_740; + ivideo->chip = SIS_740; strcpy(ivideo->myid, "SiS 740"); break; case PCI_DEVICE_ID_SI_661: - ivideo->chip = SIS_661; + ivideo->chip = SIS_661; strcpy(ivideo->myid, "SiS 661"); break; case PCI_DEVICE_ID_SI_741: - ivideo->chip = SIS_741; + ivideo->chip = SIS_741; strcpy(ivideo->myid, "SiS 741"); break; case PCI_DEVICE_ID_SI_760: - ivideo->chip = SIS_760; + ivideo->chip = SIS_760; strcpy(ivideo->myid, "SiS 760"); break; + case PCI_DEVICE_ID_SI_761: + ivideo->chip = SIS_761; + strcpy(ivideo->myid, "SiS 761"); + break; #endif + default: + break; } } @@ -4924,71 +6058,83 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, strcpy(sis_fb_info->modename, ivideo->myid); #endif - ivideo->sishw_ext.jChipType = ivideo->chip; + ivideo->SiS_Pr.ChipType = ivideo->chip; + + ivideo->SiS_Pr.ivideo = (void *)ivideo; #ifdef CONFIG_FB_SIS_315 - if((ivideo->sishw_ext.jChipType == SIS_315PRO) || - (ivideo->sishw_ext.jChipType == SIS_315)) { - ivideo->sishw_ext.jChipType = SIS_315H; + if((ivideo->SiS_Pr.ChipType == SIS_315PRO) || + (ivideo->SiS_Pr.ChipType == SIS_315)) { + ivideo->SiS_Pr.ChipType = SIS_315H; } #endif + if(!ivideo->sisvga_enabled) { + if(pci_enable_device(pdev)) { + if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge); + pci_set_drvdata(pdev, NULL); + kfree(sis_fb_info); + return -EIO; + } + } + ivideo->video_base = pci_resource_start(pdev, 0); ivideo->mmio_base = pci_resource_start(pdev, 1); ivideo->mmio_size = pci_resource_len(pdev, 1); - ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30; - ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO; - - if(!sisvga_enabled) { - if(pci_enable_device(pdev)) { - pci_set_drvdata(pdev, NULL); - kfree(sis_fb_info); - return -EIO; - } - } + ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30; + ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO; - SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress); + SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress); #ifdef CONFIG_FB_SIS_300 /* Find PCI systems for Chrontel/GPIO communication setup */ if(ivideo->chip == SIS_630) { - i=0; - do { - if(mychswtable[i].subsysVendor == ivideo->subsysvendor && - mychswtable[i].subsysCard == ivideo->subsysdevice) { - ivideo->SiS_Pr.SiS_ChSW = TRUE; - printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n", - mychswtable[i].vendorName, mychswtable[i].cardName); - break; - } - i++; - } while(mychswtable[i].subsysVendor != 0); + i = 0; + do { + if(mychswtable[i].subsysVendor == ivideo->subsysvendor && + mychswtable[i].subsysCard == ivideo->subsysdevice) { + ivideo->SiS_Pr.SiS_ChSW = TRUE; + printk(KERN_DEBUG "sisfb: Identified [%s %s] " + "requiring Chrontel/GPIO setup\n", + mychswtable[i].vendorName, + mychswtable[i].cardName); + ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL); + break; + } + i++; + } while(mychswtable[i].subsysVendor != 0); + } +#endif + +#ifdef CONFIG_FB_SIS_315 + if((ivideo->chip == SIS_760) && (ivideo->nbridge)) { + ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3)); } #endif - outSISIDXREG(SISSR, 0x05, 0x86); + outSISIDXREG(SISSR, 0x05, 0x86); - if( (!sisvga_enabled) + if( (!ivideo->sisvga_enabled) #if !defined(__i386__) && !defined(__x86_64__) - || (sisfb_resetcard) + || (sisfb_resetcard) #endif - ) { - for(i = 0x30; i <= 0x3f; i++) { - outSISIDXREG(SISCR,i,0x00); - } + ) { + for(i = 0x30; i <= 0x3f; i++) { + outSISIDXREG(SISCR, i, 0x00); + } } /* Find out about current video mode */ ivideo->modeprechange = 0x03; - inSISIDXREG(SISCR,0x34,reg); + inSISIDXREG(SISCR, 0x34, reg); if(reg & 0x7f) { ivideo->modeprechange = reg & 0x7f; - } else if(sisvga_enabled) { + } else if(ivideo->sisvga_enabled) { #if defined(__i386__) || defined(__x86_64__) - unsigned char SIS_IOTYPE2 *tt = ioremap(0, 0x1000); + unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100); if(tt) { - ivideo->modeprechange = readb(tt + 0x449); - iounmap(tt); + ivideo->modeprechange = readb(tt + 0x49); + iounmap(tt); } #endif } @@ -4996,219 +6142,221 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #ifdef MODULE if((reg & 0x80) && (reg != 0xff)) { - if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) { - printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n"); - pci_set_drvdata(pdev, NULL); - kfree(sis_fb_info); - return -EBUSY; - } + if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) + != 0xFF) { + printk(KERN_INFO "sisfb: Cannot initialize display mode, " + "X server is active\n"); + ret = -EBUSY; + goto error_4; + } } -#endif #endif - - ivideo->sishw_ext.bIntegratedMMEnabled = TRUE; -#ifdef CONFIG_FB_SIS_300 - if(ivideo->sisvga_engine == SIS_300_VGA) { - if(ivideo->chip != SIS_300) { - inSISIDXREG(SISSR, 0x1a, reg); - if(!(reg & 0x10)) { - ivideo->sishw_ext.bIntegratedMMEnabled = FALSE; - } - } - } #endif + /* Search and copy ROM image */ ivideo->bios_abase = NULL; + ivideo->SiS_Pr.VirtualRomBase = NULL; + ivideo->SiS_Pr.UseROM = FALSE; + ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE; if(ivideo->sisfb_userom) { - ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev); - ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase; - if(ivideo->sishw_ext.pjVirtualRomBase) { - printk(KERN_INFO "sisfb: Video ROM found and copied\n"); - ivideo->sishw_ext.UseROM = TRUE; - } else { - ivideo->sishw_ext.UseROM = FALSE; - printk(KERN_INFO "sisfb: Video ROM not found\n"); - } + ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev); + ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase; + ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE; + printk(KERN_INFO "sisfb: Video ROM %sfound\n", + ivideo->SiS_Pr.UseROM ? "" : "not "); + if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) { + ivideo->SiS_Pr.UseROM = FALSE; + ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE; + if( (ivideo->revision_id == 2) && + (!(ivideo->bios_abase[0x1d1] & 0x01)) ) { + ivideo->SiS_Pr.DDCPortMixup = TRUE; + } + } } else { - ivideo->sishw_ext.pjVirtualRomBase = NULL; - ivideo->sishw_ext.UseROM = FALSE; - printk(KERN_INFO "sisfb: Video ROM usage disabled\n"); + printk(KERN_INFO "sisfb: Video ROM usage disabled\n"); } - /* Find systems for special custom timing */ + /* Find systems for special custom timing */ if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) { - int j; - unsigned char *biosver = NULL; - unsigned char *biosdate = NULL; - BOOLEAN footprint; - u32 chksum = 0; - - if(ivideo->sishw_ext.UseROM) { - biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06; - biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c; - for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i]; - } - - i=0; - do { - if( (mycustomttable[i].chipID == ivideo->chip) && - ((!strlen(mycustomttable[i].biosversion)) || - (ivideo->sishw_ext.UseROM && - (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) && - ((!strlen(mycustomttable[i].biosdate)) || - (ivideo->sishw_ext.UseROM && - (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) && - ((!mycustomttable[i].bioschksum) || - (ivideo->sishw_ext.UseROM && - (mycustomttable[i].bioschksum == chksum))) && - (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) && - (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) { - footprint = TRUE; - for(j = 0; j < 5; j++) { - if(mycustomttable[i].biosFootprintAddr[j]) { - if(ivideo->sishw_ext.UseROM) { - if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] != - mycustomttable[i].biosFootprintData[j]) { - footprint = FALSE; - } - } else footprint = FALSE; - } - } - if(footprint) { - ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID; - printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n", - mycustomttable[i].vendorName, - mycustomttable[i].cardName); - printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n", - mycustomttable[i].optionName); - break; - } - } - i++; - } while(mycustomttable[i].chipID); + sisfb_detect_custom_timing(ivideo); } -#ifdef CONFIG_FB_SIS_300 - if(ivideo->sisvga_engine == SIS_300_VGA) { - if( (!sisvga_enabled) + /* POST card in case this has not been done by the BIOS */ + if( (!ivideo->sisvga_enabled) #if !defined(__i386__) && !defined(__x86_64__) - || (sisfb_resetcard) + || (sisfb_resetcard) #endif - ) { + ) { +#ifdef CONFIG_FB_SIS_300 + if(ivideo->sisvga_engine == SIS_300_VGA) { if(ivideo->chip == SIS_300) { sisfb_post_sis300(pdev); + ivideo->sisfb_can_post = 1; } } - } #endif #ifdef CONFIG_FB_SIS_315 - if(ivideo->sisvga_engine == SIS_315_VGA) { - if( (!sisvga_enabled) -#if !defined(__i386__) && !defined(__x86_64__) - || (sisfb_resetcard) -#endif - ) { - if((ivideo->chip == SIS_315H) || + if(ivideo->sisvga_engine == SIS_315_VGA) { + int result = 1; + /* if((ivideo->chip == SIS_315H) || (ivideo->chip == SIS_315) || (ivideo->chip == SIS_315PRO) || (ivideo->chip == SIS_330)) { sisfb_post_sis315330(pdev); + } else */ if(ivideo->chip == XGI_20) { + result = sisfb_post_xgi(pdev); + ivideo->sisfb_can_post = 1; + } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) { + result = sisfb_post_xgi(pdev); + ivideo->sisfb_can_post = 1; + } else { + printk(KERN_INFO "sisfb: Card is not " + "POSTed and sisfb can't do this either.\n"); + } + if(!result) { + printk(KERN_ERR "sisfb: Failed to POST card\n"); + ret = -ENODEV; + goto error_3; } } - } #endif + } + ivideo->sisfb_card_posted = 1; + + /* Find out about RAM size */ if(sisfb_get_dram_size(ivideo)) { - printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n"); - if(ivideo->bios_abase) vfree(ivideo->bios_abase); - pci_set_drvdata(pdev, NULL); - kfree(sis_fb_info); - return -ENODEV; + printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n"); + ret = -ENODEV; + goto error_3; } + + /* Enable PCI addressing and MMIO */ if((ivideo->sisfb_mode_idx < 0) || ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) { - /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */ - orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE)); - /* Enable 2D accelerator engine */ - orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D); + /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */ + orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE)); + /* Enable 2D accelerator engine */ + orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D); } if(sisfb_pdc != 0xff) { - if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c; - else sisfb_pdc &= 0x1f; - ivideo->SiS_Pr.PDC = sisfb_pdc; + if(ivideo->sisvga_engine == SIS_300_VGA) + sisfb_pdc &= 0x3c; + else + sisfb_pdc &= 0x1f; + ivideo->SiS_Pr.PDC = sisfb_pdc; } #ifdef CONFIG_FB_SIS_315 if(ivideo->sisvga_engine == SIS_315_VGA) { - if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f; + if(sisfb_pdca != 0xff) + ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f; } #endif if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) { - printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n"); + printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n", + (int)(ivideo->video_size >> 20)); printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n"); - if(ivideo->bios_abase) vfree(ivideo->bios_abase); - pci_set_drvdata(pdev, NULL); - kfree(sis_fb_info); - return -ENODEV; + ret = -ENODEV; + goto error_3; } if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) { printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n"); - release_mem_region(ivideo->video_base, ivideo->video_size); - if(ivideo->bios_abase) vfree(ivideo->bios_abase); - pci_set_drvdata(pdev, NULL); - kfree(sis_fb_info); - return -ENODEV; + ret = -ENODEV; + goto error_2; } ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size); - ivideo->sishw_ext.pjVideoMemoryAddress = ivideo->video_vbase; + ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase; if(!ivideo->video_vbase) { - printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n"); - release_mem_region(ivideo->video_base, ivideo->video_size); - release_mem_region(ivideo->mmio_base, ivideo->mmio_size); - if(ivideo->bios_abase) vfree(ivideo->bios_abase); - pci_set_drvdata(pdev, NULL); - kfree(sis_fb_info); - return -ENODEV; + printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n"); + ret = -ENODEV; + goto error_1; } ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size); if(!ivideo->mmio_vbase) { - printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n"); - iounmap(ivideo->video_vbase); - release_mem_region(ivideo->video_base, ivideo->video_size); - release_mem_region(ivideo->mmio_base, ivideo->mmio_size); - if(ivideo->bios_abase) vfree(ivideo->bios_abase); + printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n"); + ret = -ENODEV; +error_0: iounmap(ivideo->video_vbase); +error_1: release_mem_region(ivideo->video_base, ivideo->video_size); +error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size); +error_3: vfree(ivideo->bios_abase); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +error_4: +#endif + if(ivideo->lpcdev) + SIS_PCI_PUT_DEVICE(ivideo->lpcdev); + if(ivideo->nbridge) + SIS_PCI_PUT_DEVICE(ivideo->nbridge); pci_set_drvdata(pdev, NULL); - kfree(sis_fb_info); - return -ENODEV; + if(!ivideo->sisvga_enabled) + pci_disable_device(pdev); + kfree(sis_fb_info); + return ret; } - printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n", - ivideo->video_base, (ULONG)ivideo->video_vbase, ivideo->video_size / 1024); + printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n", + ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024); + + if(ivideo->video_offset) { + printk(KERN_INFO "sisfb: Viewport offset %ldk\n", + ivideo->video_offset / 1024); + } printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n", - ivideo->mmio_base, (ULONG)ivideo->mmio_vbase, ivideo->mmio_size / 1024); + ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024); + + + /* Determine the size of the command queue */ + if(ivideo->sisvga_engine == SIS_300_VGA) { + ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE; + } else { + if(ivideo->chip == XGI_20) { + ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7; + } else { + ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE; + } + } + /* Engines are no longer initialized here; this is + * now done after the first mode-switch (if the + * submitted var has its acceleration flags set). + */ + + /* Calculate the base of the (unused) hw cursor */ + ivideo->hwcursor_vbase = ivideo->video_vbase + + ivideo->video_size + - ivideo->cmdQueueSize + - ivideo->hwcursor_size; + ivideo->caps |= HW_CURSOR_CAP; + + /* Initialize offscreen memory manager */ if((ivideo->havenoheap = sisfb_heap_init(ivideo))) { printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n"); } /* Used for clearing the screen only, therefore respect our mem limit */ - ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem; + ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset; + ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem; - ivideo->mtrr = 0; + ivideo->mtrr = -1; ivideo->vbflags = 0; ivideo->lcddefmodeidx = DEFAULT_LCDMODE; ivideo->tvdefmodeidx = DEFAULT_TVMODE; ivideo->defmodeidx = DEFAULT_MODE; - ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext); + ivideo->newrom = 0; + if(ivideo->chip < XGI_20) { + if(ivideo->bios_abase) { + ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr); + } + } if((ivideo->sisfb_mode_idx < 0) || ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) { @@ -5217,192 +6365,57 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, sisfb_get_VB_type(ivideo); - if(ivideo->vbflags & VB_VIDEOBRIDGE) { + if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) { sisfb_detect_VB_connect(ivideo); } ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD); - if(ivideo->vbflags & VB_VIDEOBRIDGE) { - if(ivideo->sisfb_crt2type != -1) { - if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) { - ivideo->currentvbflags |= CRT2_LCD; - } else if(ivideo->sisfb_crt2type != CRT2_LCD) { - ivideo->currentvbflags |= ivideo->sisfb_crt2type; - } - } else { - /* Chrontel 700x TV detection often unreliable, therefore use a - * different default order on such machines - */ - if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) { - if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD; - else if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV; - else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA; - } else { - if(ivideo->vbflags & CRT2_TV) ivideo->currentvbflags |= CRT2_TV; - else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD; - else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA; - } - } + /* Decide on which CRT2 device to use */ + if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) { + if(ivideo->sisfb_crt2type != -1) { + if((ivideo->sisfb_crt2type == CRT2_LCD) && + (ivideo->vbflags & CRT2_LCD)) { + ivideo->currentvbflags |= CRT2_LCD; + } else if(ivideo->sisfb_crt2type != CRT2_LCD) { + ivideo->currentvbflags |= ivideo->sisfb_crt2type; + } + } else { + /* Chrontel 700x TV detection often unreliable, therefore + * use a different default order on such machines + */ + if((ivideo->sisvga_engine == SIS_300_VGA) && + (ivideo->vbflags2 & VB2_CHRONTEL)) { + if(ivideo->vbflags & CRT2_LCD) + ivideo->currentvbflags |= CRT2_LCD; + else if(ivideo->vbflags & CRT2_TV) + ivideo->currentvbflags |= CRT2_TV; + else if(ivideo->vbflags & CRT2_VGA) + ivideo->currentvbflags |= CRT2_VGA; + } else { + if(ivideo->vbflags & CRT2_TV) + ivideo->currentvbflags |= CRT2_TV; + else if(ivideo->vbflags & CRT2_LCD) + ivideo->currentvbflags |= CRT2_LCD; + else if(ivideo->vbflags & CRT2_VGA) + ivideo->currentvbflags |= CRT2_VGA; + } + } } if(ivideo->vbflags & CRT2_LCD) { - inSISIDXREG(SISCR, 0x36, reg); - reg &= 0x0f; - if(ivideo->sisvga_engine == SIS_300_VGA) { - ivideo->CRT2LCDType = sis300paneltype[reg]; - } else if(ivideo->chip >= SIS_661) { - ivideo->CRT2LCDType = sis661paneltype[reg]; - } else { - ivideo->CRT2LCDType = sis310paneltype[reg]; - if((ivideo->chip == SIS_550) && (sisfb_fstn)) { - if((ivideo->CRT2LCDType != LCD_640x480_2) && - (ivideo->CRT2LCDType != LCD_640x480_3)) { - ivideo->CRT2LCDType = LCD_320x480; - } - } - } - if(ivideo->CRT2LCDType == LCD_UNKNOWN) { - /* For broken BIOSes: Assume 1024x768, RGB18 */ - ivideo->CRT2LCDType = LCD_1024x768; - setSISIDXREG(SISCR,0x36,0xf0,0x02); - setSISIDXREG(SISCR,0x37,0xee,0x01); - printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg); - } - for(i = 0; i < SIS_LCD_NUMBER; i++) { - if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) { - ivideo->lcdxres = sis_lcd_data[i].xres; - ivideo->lcdyres = sis_lcd_data[i].yres; - ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx; - break; - } - } - if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) { - ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99; - } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) { - ivideo->lcdxres = 848; ivideo->lcdyres = 480; ivideo->lcddefmodeidx = 47; - } - printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n", - ivideo->lcdxres, ivideo->lcdyres); - } - -#ifdef CONFIG_FB_SIS_300 - /* Save the current PanelDelayCompensation if the LCD is currently used */ - if(ivideo->sisvga_engine == SIS_300_VGA) { - if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) { - int tmp; - inSISIDXREG(SISCR,0x30,tmp); - if(tmp & 0x20) { - /* Currently on LCD? If yes, read current pdc */ - inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc); - ivideo->detectedpdc &= 0x3c; - if(ivideo->SiS_Pr.PDC == -1) { - /* Let option override detection */ - ivideo->SiS_Pr.PDC = ivideo->detectedpdc; - } - printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n", - ivideo->detectedpdc); - } - if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) { - printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n", - ivideo->SiS_Pr.PDC); - } - } + sisfb_detect_lcd_type(ivideo); } -#endif - -#ifdef CONFIG_FB_SIS_315 - if(ivideo->sisvga_engine == SIS_315_VGA) { - - /* Try to find about LCDA */ - if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) { - int tmp; - inSISIDXREG(SISPART1,0x13,tmp); - if(tmp & 0x04) { - ivideo->SiS_Pr.SiS_UseLCDA = TRUE; - ivideo->detectedlcda = 0x03; - } - } - - /* Save PDC */ - if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) { - int tmp; - inSISIDXREG(SISCR,0x30,tmp); - if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) { - /* Currently on LCD? If yes, read current pdc */ - u8 pdc; - inSISIDXREG(SISPART1,0x2D,pdc); - ivideo->detectedpdc = (pdc & 0x0f) << 1; - ivideo->detectedpdca = (pdc & 0xf0) >> 3; - inSISIDXREG(SISPART1,0x35,pdc); - ivideo->detectedpdc |= ((pdc >> 7) & 0x01); - inSISIDXREG(SISPART1,0x20,pdc); - ivideo->detectedpdca |= ((pdc >> 6) & 0x01); - if(ivideo->newrom) { - /* New ROM invalidates other PDC resp. */ - if(ivideo->detectedlcda != 0xff) { - ivideo->detectedpdc = 0xff; - } else { - ivideo->detectedpdca = 0xff; - } - } - if(ivideo->SiS_Pr.PDC == -1) { - if(ivideo->detectedpdc != 0xff) { - ivideo->SiS_Pr.PDC = ivideo->detectedpdc; - } - } - if(ivideo->SiS_Pr.PDCA == -1) { - if(ivideo->detectedpdca != 0xff) { - ivideo->SiS_Pr.PDCA = ivideo->detectedpdca; - } - } - if(ivideo->detectedpdc != 0xff) { - printk(KERN_INFO - "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n", - ivideo->detectedpdc); - } - if(ivideo->detectedpdca != 0xff) { - printk(KERN_INFO - "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n", - ivideo->detectedpdca); - } - } - - /* Save EMI */ - if(ivideo->vbflags & (VB_302LV | VB_302ELV)) { - inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30); - inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31); - inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32); - inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33); - ivideo->SiS_Pr.HaveEMI = TRUE; - if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) { - ivideo->SiS_Pr.HaveEMILCD = TRUE; - } - } - } - /* Let user override detected PDCs (all bridges) */ - if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) { - if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) { - printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n", - ivideo->SiS_Pr.PDC); - } - if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) { - printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n", - ivideo->SiS_Pr.PDCA); - } - } - - } -#endif + sisfb_save_pdc_emi(ivideo); if(!ivideo->sisfb_crt1off) { - sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0); + sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0); } else { - if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) && - (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) { - sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1); - } + if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) && + (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) { + sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1); + } } if(ivideo->sisfb_mode_idx >= 0) { @@ -5434,7 +6447,8 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]; if(ivideo->refresh_rate != 0) { - sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx); + sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, + ivideo->sisfb_mode_idx); } if(ivideo->rate_idx == 0) { @@ -5443,9 +6457,12 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, } if(ivideo->sisfb_thismonitor.datavalid) { - if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx, - ivideo->rate_idx, ivideo->refresh_rate)) { - printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); + if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, + ivideo->sisfb_mode_idx, + ivideo->rate_idx, + ivideo->refresh_rate)) { + printk(KERN_INFO "sisfb: WARNING: Refresh rate " + "exceeds monitor specs!\n"); } } @@ -5454,28 +6471,34 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres; sisfb_set_vparms(ivideo); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - /* ---------------- For 2.4: Now switch the mode ------------------ */ - - printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n", - ivideo->video_width, ivideo->video_height, ivideo->video_bpp, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + + /* ---------------- For 2.4: Now switch the mode ------------------ */ + + printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n", + ivideo->video_width, ivideo->video_height, ivideo->video_bpp, ivideo->refresh_rate); + /* Determine whether or not acceleration is to be + * used. Need to know before pre/post_set_mode() + */ + ivideo->accel = 0; + ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT; + if(ivideo->sisfb_accel) { + ivideo->accel = -1; + ivideo->default_var.accel_flags |= FB_ACCELF_TEXT; + } + + /* Now switch the mode */ sisfb_pre_setmode(ivideo); - if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) { + if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) { printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n", ivideo->mode_no); - iounmap(ivideo->video_vbase); + ret = -EINVAL; iounmap(ivideo->mmio_vbase); - release_mem_region(ivideo->video_base, ivideo->video_size); - release_mem_region(ivideo->mmio_base, ivideo->mmio_size); - if(ivideo->bios_abase) vfree(ivideo->bios_abase); - pci_set_drvdata(pdev, NULL); - kfree(sis_fb_info); - return -EINVAL; + goto error_0; } outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); @@ -5488,18 +6511,17 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, /* Force reset of x virtual in crtc_to_var */ ivideo->default_var.xres_virtual = 0; + /* Copy mode timing to var */ sisfb_crtc_to_var(ivideo, &ivideo->default_var); + /* Find out about screen pitch */ sisfb_calc_pitch(ivideo, &ivideo->default_var); sisfb_set_pitch(ivideo); - ivideo->accel = 0; - if(ivideo->sisfb_accel) { - ivideo->accel = -1; - ivideo->default_var.accel_flags |= FB_ACCELF_TEXT; - } + /* Init the accelerator (does nothing currently) */ sisfb_initaccel(ivideo); - + + /* Init some fbinfo entries */ sis_fb_info->node = -1; sis_fb_info->flags = FBINFO_FLAG_DEFAULT; sis_fb_info->fbops = &sisfb_ops; @@ -5515,41 +6537,42 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, #else /* --------- For 2.6: Setup a somewhat sane default var ------------ */ printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n", - ivideo->video_width, ivideo->video_height, ivideo->video_bpp, + ivideo->video_width, ivideo->video_height, ivideo->video_bpp, ivideo->refresh_rate); + /* Set up the default var according to chosen default display mode */ ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width; ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height; ivideo->default_var.bits_per_pixel = ivideo->video_bpp; sisfb_bpp_to_var(ivideo, &ivideo->default_var); - + ivideo->default_var.pixclock = (u32) (1000000000 / - sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext, - ivideo->mode_no, ivideo->rate_idx)); - - if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext, - ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) { - if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { - ivideo->default_var.pixclock <<= 1; - } - } + sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx)); + + if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no, + ivideo->rate_idx, &ivideo->default_var)) { + if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + ivideo->default_var.pixclock <<= 1; + } + } if(ivideo->sisfb_ypan) { - /* Maximize regardless of sisfb_max at startup */ - ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var); - if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) { - ivideo->default_var.yres_virtual = ivideo->default_var.yres; - } + /* Maximize regardless of sisfb_max at startup */ + ivideo->default_var.yres_virtual = + sisfb_calc_maxyres(ivideo, &ivideo->default_var); + if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) { + ivideo->default_var.yres_virtual = ivideo->default_var.yres; + } } sisfb_calc_pitch(ivideo, &ivideo->default_var); ivideo->accel = 0; if(ivideo->sisfb_accel) { - ivideo->accel = -1; + ivideo->accel = -1; #ifdef STUPID_ACCELF_TEXT_SHIT - ivideo->default_var.accel_flags |= FB_ACCELF_TEXT; + ivideo->default_var.accel_flags |= FB_ACCELF_TEXT; #endif } sisfb_initaccel(ivideo); @@ -5566,21 +6589,21 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, #endif sis_fb_info->var = ivideo->default_var; sis_fb_info->fix = ivideo->sisfb_fix; - sis_fb_info->screen_base = ivideo->video_vbase; + sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset; sis_fb_info->fbops = &sisfb_ops; sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info); sis_fb_info->pseudo_palette = ivideo->pseudo_palette; - + fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0); #endif /* 2.6 */ - printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags); + printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags); #ifdef CONFIG_MTRR ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size, MTRR_TYPE_WRCOMB, 1); - if(!ivideo->mtrr) { + if(ivideo->mtrr < 0) { printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n"); } #endif @@ -5591,14 +6614,9 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, if(register_framebuffer(sis_fb_info) < 0) { printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n"); - iounmap(ivideo->video_vbase); + ret = -EINVAL; iounmap(ivideo->mmio_vbase); - release_mem_region(ivideo->video_base, ivideo->video_size); - release_mem_region(ivideo->mmio_base, ivideo->mmio_size); - if(ivideo->bios_abase) vfree(ivideo->bios_abase); - pci_set_drvdata(pdev, NULL); - kfree(sis_fb_info); - return -EINVAL; + goto error_0; } ivideo->registered = 1; @@ -5607,21 +6625,47 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, ivideo->next = card_list; card_list = ivideo; +#ifdef SIS_OLD_CONFIG_COMPAT + { + int ret; + /* Our ioctls are all "32/64bit compatible" */ + ret = register_ioctl32_conversion(FBIO_ALLOC, NULL); + ret |= register_ioctl32_conversion(FBIO_FREE, NULL); + ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL); + ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL); + ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL); + ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL); + ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL); + ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL); + ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL); + ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL); + ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL); + ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL); + if(ret) + printk(KERN_ERR + "sisfb: Error registering ioctl32 translations\n"); + else + ivideo->ioctl32registered = 1; + } +#endif + printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n", - ivideo->sisfb_accel ? "enabled" : "disabled", - ivideo->sisfb_ypan ? - (ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled"); + ivideo->sisfb_accel ? "enabled" : "disabled", + ivideo->sisfb_ypan ? + (ivideo->sisfb_max ? "enabled (auto-max)" : + "enabled (no auto-max)") : + "disabled"); - printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n", + printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n", #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - GET_FB_IDX(sis_fb_info->node), + GET_FB_IDX(sis_fb_info->node), #else - sis_fb_info->node, + sis_fb_info->node, #endif ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL); - printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n"); + printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n"); } /* if mode = "none" */ @@ -5634,26 +6678,62 @@ static int __devinit sisfb_probe(struct pci_dev *pdev, static void __devexit sisfb_remove(struct pci_dev *pdev) { - struct sis_video_info *ivideo = pci_get_drvdata(pdev); - struct fb_info *sis_fb_info = ivideo->memyselfandi; - int registered = ivideo->registered; + struct sis_video_info *ivideo = pci_get_drvdata(pdev); + struct fb_info *sis_fb_info = ivideo->memyselfandi; + int registered = ivideo->registered; + int modechanged = ivideo->modechanged; + +#ifdef SIS_OLD_CONFIG_COMPAT + if(ivideo->ioctl32registered) { + int ret; + ret = unregister_ioctl32_conversion(FBIO_ALLOC); + ret |= unregister_ioctl32_conversion(FBIO_FREE); + ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK); + ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE); + ret |= unregister_ioctl32_conversion(SISFB_GET_INFO); + ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET); + ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET); + ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK); + ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS); + ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE); + ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE); + ret |= unregister_ioctl32_conversion(SISFB_COMMAND); + if(ret) + printk(KERN_ERR + "sisfb: Error unregistering ioctl32 translations\n"); + } +#endif /* Unmap */ - iounmap(ivideo->video_vbase); iounmap(ivideo->mmio_vbase); - vfree(ivideo->bios_abase); + iounmap(ivideo->video_vbase); /* Release mem regions */ release_mem_region(ivideo->video_base, ivideo->video_size); release_mem_region(ivideo->mmio_base, ivideo->mmio_size); + vfree(ivideo->bios_abase); + + if(ivideo->lpcdev) + SIS_PCI_PUT_DEVICE(ivideo->lpcdev); + + if(ivideo->nbridge) + SIS_PCI_PUT_DEVICE(ivideo->nbridge); + #ifdef CONFIG_MTRR /* Release MTRR region */ - if(ivideo->mtrr) { + if(ivideo->mtrr >= 0) mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size); - } #endif + pci_set_drvdata(pdev, NULL); + + /* If device was disabled when starting, disable + * it when quitting. + */ + if(!ivideo->sisvga_enabled) + pci_disable_device(pdev); + /* Unregister the framebuffer */ if(ivideo->registered) { unregister_framebuffer(sis_fb_info); @@ -5664,7 +6744,7 @@ static void __devexit sisfb_remove(struct pci_dev *pdev) #endif } - pci_set_drvdata(pdev, NULL); + /* OK, our ivideo is gone for good from here. */ /* TODO: Restore the initial mode * This sounds easy but is as good as impossible @@ -5673,15 +6753,15 @@ static void __devexit sisfb_remove(struct pci_dev *pdev) * from machine to machine. Depends on the type * of integration between chipset and bridge. */ - if(registered) { - printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n"); - } + if(registered && modechanged) + printk(KERN_INFO + "sisfb: Restoring of text mode not supported yet\n"); }; static struct pci_driver sisfb_driver = { .name = "sisfb", .id_table = sisfb_pci_table, - .probe = sisfb_probe, + .probe = sisfb_probe, .remove = __devexit_p(sisfb_remove) }; @@ -5693,10 +6773,11 @@ SISINITSTATIC int __init sisfb_init(void) if(fb_get_options("sisfb", &options)) return -ENODEV; + sisfb_setup(options); #endif #endif - return(pci_register_driver(&sisfb_driver)); + return pci_register_driver(&sisfb_driver); } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) @@ -5711,36 +6792,129 @@ module_init(sisfb_init); #ifdef MODULE -static char *mode = NULL; -static int vesa = -1; -static unsigned int rate = 0; -static unsigned int crt1off = 1; -static unsigned int mem = 0; -static char *forcecrt2type = NULL; -static int forcecrt1 = -1; -static int pdc = -1; -static int pdc1 = -1; -static int noaccel = -1; -static int noypan = -1; -static int nomax = -1; +static char *mode = NULL; +static int vesa = -1; +static unsigned int rate = 0; +static unsigned int crt1off = 1; +static unsigned int mem = 0; +static char *forcecrt2type = NULL; +static int forcecrt1 = -1; +static int pdc = -1; +static int pdc1 = -1; +static int noaccel = -1; +static int noypan = -1; +static int nomax = -1; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static int inverse = 0; +#endif +static int userom = -1; +static int useoem = -1; +static char *tvstandard = NULL; +static int nocrt2rate = 0; +static int scalelcd = -1; +static char *specialtiming = NULL; +static int lvdshl = -1; +static int tvxposoffset = 0, tvyposoffset = 0; +#if !defined(__i386__) && !defined(__x86_64__) +static int resetcard = 0; +static int videoram = 0; +#endif + +static int __init sisfb_init_module(void) +{ + sisfb_setdefaultparms(); + + if(rate) + sisfb_parm_rate = rate; + + if((scalelcd == 0) || (scalelcd == 1)) + sisfb_scalelcd = scalelcd ^ 1; + + /* Need to check crt2 type first for fstn/dstn */ + + if(forcecrt2type) + sisfb_search_crt2type(forcecrt2type); + + if(tvstandard) + sisfb_search_tvstd(tvstandard); + + if(mode) + sisfb_search_mode(mode, FALSE); + else if(vesa != -1) + sisfb_search_vesamode(vesa, FALSE); + + sisfb_crt1off = (crt1off == 0) ? 1 : 0; + + sisfb_forcecrt1 = forcecrt1; + if(forcecrt1 == 1) + sisfb_crt1off = 0; + else if(forcecrt1 == 0) + sisfb_crt1off = 1; + + if(noaccel == 1) + sisfb_accel = 0; + else if(noaccel == 0) + sisfb_accel = 1; + + if(noypan == 1) + sisfb_ypan = 0; + else if(noypan == 0) + sisfb_ypan = 1; + + if(nomax == 1) + sisfb_max = 0; + else if(nomax == 0) + sisfb_max = 1; + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -static int inverse = 0; -#endif -static int userom = -1; -static int useoem = -1; -static char *tvstandard = NULL; -static int nocrt2rate = 0; -static int scalelcd = -1; -static char *specialtiming = NULL; -static int lvdshl = -1; -static int tvxposoffset = 0, tvyposoffset = 0; -static int filter = -1; + if(inverse) sisfb_inverse = 1; +#endif + + if(mem) + sisfb_parm_mem = mem; + + if(userom != -1) + sisfb_userom = userom; + + if(useoem != -1) + sisfb_useoem = useoem; + + if(pdc != -1) + sisfb_pdc = (pdc & 0x7f); + + if(pdc1 != -1) + sisfb_pdca = (pdc1 & 0x1f); + + sisfb_nocrt2rate = nocrt2rate; + + if(specialtiming) + sisfb_search_specialtiming(specialtiming); + + if((lvdshl >= 0) && (lvdshl <= 3)) + sisfb_lvdshl = lvdshl; + + sisfb_tvxposoffset = tvxposoffset; + sisfb_tvyposoffset = tvyposoffset; + #if !defined(__i386__) && !defined(__x86_64__) -static int resetcard = 0; -static int videoram = 0; + sisfb_resetcard = (resetcard) ? 1 : 0; + if(videoram) + sisfb_videoram = videoram; #endif -MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver"); + return sisfb_init(); +} + +static void __exit sisfb_remove_module(void) +{ + pci_unregister_driver(&sisfb_driver); + printk(KERN_DEBUG "sisfb: Module unloaded\n"); +} + +module_init(sisfb_init_module); +module_exit(sisfb_remove_module); + +MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others"); @@ -5764,7 +6938,6 @@ MODULE_PARM(lvdshl, "i"); MODULE_PARM(tvstandard, "s"); MODULE_PARM(tvxposoffset, "i"); MODULE_PARM(tvyposoffset, "i"); -MODULE_PARM(filter, "i"); MODULE_PARM(nocrt2rate, "i"); MODULE_PARM(inverse, "i"); #if !defined(__i386__) && !defined(__x86_64__) @@ -5793,7 +6966,6 @@ module_param(lvdshl, int, 0); module_param(tvstandard, charp, 0); module_param(tvxposoffset, int, 0); module_param(tvyposoffset, int, 0); -module_param(filter, int, 0); module_param(nocrt2rate, int, 0); #if !defined(__i386__) && !defined(__x86_64__) module_param(resetcard, int, 0); @@ -5801,25 +6973,35 @@ module_param(videoram, int, 0); #endif #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MODULE_PARM_DESC(mem, "\nDetermines the beginning of the video memory heap in KB. This heap is used\n" "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n" "on the amount of video RAM available. If 8MB of video RAM or less is available,\n" "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n" - "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n" + "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n" "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n" "for XFree86 4.x/X.org 6.7 and later.\n"); +#else +MODULE_PARM_DESC(mem, + "\nDetermines the beginning of the video memory heap in KB. This heap is used\n" + "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n" + "on the amount of video RAM available. If 8MB of video RAM or less is available,\n" + "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n" + "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n" + "The value is to be specified without 'KB'.\n"); +#endif MODULE_PARM_DESC(noaccel, - "\nIf set to anything other than 0, 2D acceleration will be disabled.\n" + "\nIf set to anything other than 0, 2D acceleration will be disabled.\n" "(default: 0)\n"); MODULE_PARM_DESC(noypan, - "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n" - "will be performed by redrawing the screen. (default: 0)\n"); + "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n" + "will be performed by redrawing the screen. (default: 0)\n"); MODULE_PARM_DESC(nomax, - "\nIf y-panning is enabled, sisfb will by default use the entire available video\n" + "\nIf y-panning is enabled, sisfb will by default use the entire available video\n" "memory for the virtual screen in order to optimize scrolling performance. If\n" "this is set to anything other than 0, sisfb will not do this and thereby \n" "enable the user to positively specify a virtual Y size of the screen using\n" @@ -5827,30 +7009,30 @@ MODULE_PARM_DESC(nomax, #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MODULE_PARM_DESC(mode, - "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n" - "1024x768x16. Other formats supported include XxY-Depth and\n" - "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n" + "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n" + "1024x768x16. Other formats supported include XxY-Depth and\n" + "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n" "number, it will be interpreted as a VESA mode number. (default: none if\n" "sisfb is a module; this leaves the console untouched and the driver will\n" "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n" "is in the kernel)\n"); MODULE_PARM_DESC(vesa, - "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n" - "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n" + "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n" + "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n" "and the driver will only do the video memory management for eg. DRM/DRI;\n" "0x0103 if sisfb is in the kernel)\n"); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) MODULE_PARM_DESC(mode, - "\nSelects the desired default display mode in the format XxYxDepth,\n" - "eg. 1024x768x16. Other formats supported include XxY-Depth and\n" + "\nSelects the desired default display mode in the format XxYxDepth,\n" + "eg. 1024x768x16. Other formats supported include XxY-Depth and\n" "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n" "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n"); MODULE_PARM_DESC(vesa, - "\nSelects the desired default display mode by VESA defined mode number, eg.\n" - "0x117 (default: 0x0103)\n"); + "\nSelects the desired default display mode by VESA defined mode number, eg.\n" + "0x117 (default: 0x0103)\n"); #endif MODULE_PARM_DESC(rate, @@ -5880,16 +7062,16 @@ MODULE_PARM_DESC(scalelcd, "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n"); MODULE_PARM_DESC(pdc, - "\nThis is for manually selecting the LCD panel delay compensation. The driver\n" + "\nThis is for manually selecting the LCD panel delay compensation. The driver\n" "should detect this correctly in most cases; however, sometimes this is not\n" "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n" - "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n" - "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n" - "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n"); + "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n" + "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n" + "value from 0 to 31). (default: autodetected, if LCD is active during start)\n"); #ifdef CONFIG_FB_SIS_315 MODULE_PARM_DESC(pdc1, - "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n" + "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n" "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n" "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n" "implemented yet.\n"); @@ -5913,17 +7095,13 @@ MODULE_PARM_DESC(tvyposoffset, "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n" "Default: 0\n"); -MODULE_PARM_DESC(filter, - "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n" - "(Possible values 0-7, default: [no filter])\n"); - MODULE_PARM_DESC(nocrt2rate, "\nSetting this to 1 will force the driver to use the default refresh rate for\n" "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n"); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MODULE_PARM_DESC(inverse, - "\nSetting this to anything but 0 should invert the display colors, but this\n" + "\nSetting this to anything but 0 should invert the display colors, but this\n" "does not seem to work. (default: 0)\n"); #endif @@ -5931,98 +7109,23 @@ MODULE_PARM_DESC(inverse, #ifdef CONFIG_FB_SIS_300 MODULE_PARM_DESC(resetcard, "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n" - "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n" - "Default: 0\n"); + "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n" + "currently). Default: 0\n"); MODULE_PARM_DESC(videoram, "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n" "some non-x86 architectures where the memory auto detection fails. Only\n" - "relevant if resetcard is set, too. Default: [auto-detect]\n"); -#endif -#endif - -static int __devinit sisfb_init_module(void) -{ - sisfb_setdefaultparms(); - - if(rate) sisfb_parm_rate = rate; - - if((scalelcd == 0) || (scalelcd == 1)) { - sisfb_scalelcd = scalelcd ^ 1; - } - - /* Need to check crt2 type first for fstn/dstn */ - - if(forcecrt2type) - sisfb_search_crt2type(forcecrt2type); - - if(tvstandard) - sisfb_search_tvstd(tvstandard); - - if(mode) - sisfb_search_mode(mode, FALSE); - else if(vesa != -1) - sisfb_search_vesamode(vesa, FALSE); - - sisfb_crt1off = (crt1off == 0) ? 1 : 0; - - sisfb_forcecrt1 = forcecrt1; - if(forcecrt1 == 1) sisfb_crt1off = 0; - else if(forcecrt1 == 0) sisfb_crt1off = 1; - - if(noaccel == 1) sisfb_accel = 0; - else if(noaccel == 0) sisfb_accel = 1; - - if(noypan == 1) sisfb_ypan = 0; - else if(noypan == 0) sisfb_ypan = 1; - - if(nomax == 1) sisfb_max = 0; - else if(nomax == 0) sisfb_max = 1; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - if(inverse) sisfb_inverse = 1; + "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n"); #endif - - if(mem) sisfb_parm_mem = mem; - - if(userom != -1) sisfb_userom = userom; - if(useoem != -1) sisfb_useoem = useoem; - - if(pdc != -1) sisfb_pdc = (pdc & 0x7f); - if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f); - - sisfb_nocrt2rate = nocrt2rate; - - if(specialtiming) - sisfb_search_specialtiming(specialtiming); - - if((lvdshl >= 0) && (lvdshl <= 3)) sisfb_lvdshl = lvdshl; - - if(filter != -1) sisfb_filter = filter; - - sisfb_tvxposoffset = tvxposoffset; - sisfb_tvyposoffset = tvyposoffset; - -#if !defined(__i386__) && !defined(__x86_64__) - sisfb_resetcard = (resetcard) ? 1 : 0; - if(videoram) sisfb_videoram = videoram; #endif - return(sisfb_init()); -} - -static void __exit sisfb_remove_module(void) -{ - pci_unregister_driver(&sisfb_driver); - printk(KERN_DEBUG "sisfb: Module unloaded\n"); -} - -module_init(sisfb_init_module); -module_exit(sisfb_remove_module); - #endif /* /MODULE */ +/* _GPL only for new symbols. */ EXPORT_SYMBOL(sis_malloc); EXPORT_SYMBOL(sis_free); +EXPORT_SYMBOL_GPL(sis_malloc_new); +EXPORT_SYMBOL_GPL(sis_free_new); + diff --git a/drivers/video/sis/sis_main.h b/drivers/video/sis/sis_main.h index a6678a7aff35d..445bcbba03aef 100644 --- a/drivers/video/sis/sis_main.h +++ b/drivers/video/sis/sis_main.h @@ -1,9 +1,10 @@ /* - * SiS 300/305/540/630(S)/730(S) - * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760 + * SiS 300/305/540/630(S)/730(S), + * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX], + * XGI V3XT/V5/V8, Z7 * frame buffer driver for Linux kernels >=2.4.14 and >=2.6.3 * - * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria. + * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria. * * 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 @@ -23,13 +24,9 @@ #ifndef _SISFB_MAIN #define _SISFB_MAIN -#include <linux/spinlock.h> - #include "vstruct.h" #include "sis.h" -#define MODE_INDEX_NONE 0 /* index for mode=none */ - /* Fbcon stuff */ static struct fb_var_screeninfo my_default_var = { .xres = 0, @@ -60,6 +57,8 @@ static struct fb_var_screeninfo my_default_var = { .vmode = FB_VMODE_NONINTERLACED, }; +#define MODE_INDEX_NONE 0 /* index for mode=none */ + /* Boot-time parameters */ static int sisfb_off = 0; static int sisfb_parm_mem = 0; @@ -93,7 +92,6 @@ static int sisfb_tvplug = -1; /* Tv plug type (for overriding autodetection) */ static int sisfb_tvstd = -1; static int sisfb_tvxposoffset = 0; static int sisfb_tvyposoffset = 0; -static int sisfb_filter = -1; static int sisfb_nocrt2rate = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) static int sisfb_inverse = 0; @@ -106,12 +104,12 @@ static int sisfb_videoram = 0; /* List of supported chips */ static struct sisfb_chip_info { - int chip; - int vgaengine; + int chip; + int vgaengine; int mni; - int hwcursor_size; + int hwcursor_size; int CRT2_write_enable; - const char *chip_name; + const char *chip_name; } sisfb_chip_info[] __devinitdata = { { SIS_300, SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 300/305" }, { SIS_540, SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 540" }, @@ -123,6 +121,8 @@ static struct sisfb_chip_info { { SIS_650, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 650" }, { SIS_330, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 330" }, { SIS_660, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 660" }, + { XGI_20, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "XGI Z7" }, + { XGI_40, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "XGI V3XT/V5/V8" }, }; static struct pci_device_id __devinitdata sisfb_pci_table[] = { @@ -139,6 +139,8 @@ static struct pci_device_id __devinitdata sisfb_pci_table[] = { { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, + { PCI_VENDOR_ID_XGI,PCI_DEVICE_ID_XGI_20, PCI_ANY_ID, PCI_ANY_ID, 0, 0,10}, + { PCI_VENDOR_ID_XGI,PCI_DEVICE_ID_XGI_40, PCI_ANY_ID, PCI_ANY_ID, 0, 0,11}, #endif { 0 } }; @@ -147,13 +149,12 @@ MODULE_DEVICE_TABLE(pci, sisfb_pci_table); static struct sis_video_info *card_list = NULL; -/* TODO: This is not handled card-wise because the DRM - does not refer to a unique fb when calling sis_alloc - or sis_free. Therefore, this is handled globally for - now (hoping that nobody is crazy enough to run two - SiS cards at the same time). +/* The memory heap is now handled card-wise, by using + sis_malloc_new/sis_free_new. However, the DRM does + not do this yet. Until it does, we keep a "global" + heap which is actually the first card's one. */ -static SIS_HEAP sisfb_heap; +static struct SIS_HEAP *sisfb_heap; #define MD_SIS300 1 #define MD_SIS315 2 @@ -181,8 +182,10 @@ static const struct _sisbios_mode { {"320x240x16", {0x56,0x56}, 0x0135, 0x0000, 320, 240, 16, 1, 40, 15, MD_SIS300|MD_SIS315}, {"320x240x24", {0x53,0x53}, 0x0000, 0x0000, 320, 240, 32, 1, 40, 15, MD_SIS300|MD_SIS315}, {"320x240x32", {0x53,0x53}, 0x0000, 0x0000, 320, 240, 32, 1, 40, 15, MD_SIS300|MD_SIS315}, - {"320x240x8", {0x5a,0x5a}, 0x0132, 0x0000, 320, 480, 8, 1, 40, 30, MD_SIS315}, /* FSTN */ -/*10*/ {"320x240x16", {0x5b,0x5b}, 0x0135, 0x0000, 320, 480, 16, 1, 40, 30, MD_SIS315}, /* FSTN */ +#define MODE_FSTN_8 9 +#define MODE_FSTN_16 10 + {"320x240x8", {0x5a,0x5a}, 0x0132, 0x0000, 320, 240, 8, 1, 40, 15, MD_SIS315}, /* FSTN */ +/*10*/ {"320x240x16", {0x5b,0x5b}, 0x0135, 0x0000, 320, 240, 16, 1, 40, 15, MD_SIS315}, /* FSTN */ {"400x300x8", {0x51,0x51}, 0x0133, 0x0000, 400, 300, 8, 1, 50, 18, MD_SIS300|MD_SIS315}, {"400x300x16", {0x57,0x57}, 0x0136, 0x0000, 400, 300, 16, 1, 50, 18, MD_SIS300|MD_SIS315}, {"400x300x24", {0x54,0x54}, 0x0000, 0x0000, 400, 300, 32, 1, 50, 18, MD_SIS300|MD_SIS315}, @@ -215,18 +218,20 @@ static const struct _sisbios_mode { /*40*/ {"800x480x16", {0x7a,0x7a}, 0x0000, 0x0000, 800, 480, 16, 1, 100, 30, MD_SIS300|MD_SIS315}, {"800x480x24", {0x76,0x76}, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, MD_SIS300|MD_SIS315}, {"800x480x32", {0x76,0x76}, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, MD_SIS300|MD_SIS315}, -#define DEFAULT_MODE 43 /* index for 800x600x8 */ -#define DEFAULT_LCDMODE 43 /* index for 800x600x8 */ -#define DEFAULT_TVMODE 43 /* index for 800x600x8 */ +#define DEFAULT_MODE 43 /* index for 800x600x8 */ +#define DEFAULT_LCDMODE 43 /* index for 800x600x8 */ +#define DEFAULT_TVMODE 43 /* index for 800x600x8 */ {"800x600x8", {0x30,0x30}, 0x0103, 0x0103, 800, 600, 8, 2, 100, 37, MD_SIS300|MD_SIS315}, {"800x600x16", {0x47,0x47}, 0x0114, 0x0114, 800, 600, 16, 2, 100, 37, MD_SIS300|MD_SIS315}, {"800x600x24", {0x63,0x63}, 0x013b, 0x0115, 800, 600, 32, 2, 100, 37, MD_SIS300|MD_SIS315}, {"800x600x32", {0x63,0x63}, 0x013b, 0x0115, 800, 600, 32, 2, 100, 37, MD_SIS300|MD_SIS315}, {"848x480x8", {0x39,0x39}, 0x0000, 0x0000, 848, 480, 8, 2, 106, 30, MD_SIS300|MD_SIS315}, +#define DEFAULT_MODE_848 48 {"848x480x16", {0x3b,0x3b}, 0x0000, 0x0000, 848, 480, 16, 2, 106, 30, MD_SIS300|MD_SIS315}, {"848x480x24", {0x3e,0x3e}, 0x0000, 0x0000, 848, 480, 32, 2, 106, 30, MD_SIS300|MD_SIS315}, /*50*/ {"848x480x32", {0x3e,0x3e}, 0x0000, 0x0000, 848, 480, 32, 2, 106, 30, MD_SIS300|MD_SIS315}, {"856x480x8", {0x3f,0x3f}, 0x0000, 0x0000, 856, 480, 8, 2, 107, 30, MD_SIS300|MD_SIS315}, +#define DEFAULT_MODE_856 52 {"856x480x16", {0x42,0x42}, 0x0000, 0x0000, 856, 480, 16, 2, 107, 30, MD_SIS300|MD_SIS315}, {"856x480x24", {0x45,0x45}, 0x0000, 0x0000, 856, 480, 32, 2, 107, 30, MD_SIS300|MD_SIS315}, {"856x480x32", {0x45,0x45}, 0x0000, 0x0000, 856, 480, 32, 2, 107, 30, MD_SIS300|MD_SIS315}, @@ -270,42 +275,47 @@ static const struct _sisbios_mode { {"1280x800x16", {0x15,0x15}, 0x0000, 0x0000, 1280, 800, 16, 1, 160, 50, MD_SIS315}, {"1280x800x24", {0x16,0x16}, 0x0000, 0x0000, 1280, 800, 32, 1, 160, 50, MD_SIS315}, {"1280x800x32", {0x16,0x16}, 0x0000, 0x0000, 1280, 800, 32, 1, 160, 50, MD_SIS315}, + {"1280x854x8", {0x14,0x14}, 0x0000, 0x0000, 1280, 854, 8, 1, 160, 53, MD_SIS315}, + {"1280x854x16", {0x15,0x15}, 0x0000, 0x0000, 1280, 854, 16, 1, 160, 53, MD_SIS315}, + {"1280x854x24", {0x16,0x16}, 0x0000, 0x0000, 1280, 854, 32, 1, 160, 53, MD_SIS315}, + {"1280x854x32", {0x16,0x16}, 0x0000, 0x0000, 1280, 854, 32, 1, 160, 53, MD_SIS315}, {"1280x960x8", {0x7c,0x7c}, 0x0000, 0x0000, 1280, 960, 8, 1, 160, 60, MD_SIS300|MD_SIS315}, - {"1280x960x16", {0x7d,0x7d}, 0x0000, 0x0000, 1280, 960, 16, 1, 160, 60, MD_SIS300|MD_SIS315}, +/*100*/ {"1280x960x16", {0x7d,0x7d}, 0x0000, 0x0000, 1280, 960, 16, 1, 160, 60, MD_SIS300|MD_SIS315}, {"1280x960x24", {0x7e,0x7e}, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_SIS300|MD_SIS315}, {"1280x960x32", {0x7e,0x7e}, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_SIS300|MD_SIS315}, {"1280x1024x8", {0x3a,0x3a}, 0x0107, 0x0107, 1280, 1024, 8, 2, 160, 64, MD_SIS300|MD_SIS315}, -/*100*/ {"1280x1024x16", {0x4d,0x4d}, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315}, + {"1280x1024x16", {0x4d,0x4d}, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315}, {"1280x1024x24", {0x65,0x65}, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315}, {"1280x1024x32", {0x65,0x65}, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315}, {"1360x768x8", {0x48,0x48}, 0x0000, 0x0000, 1360, 768, 8, 1, 170, 48, MD_SIS300|MD_SIS315}, {"1360x768x16", {0x4b,0x4b}, 0x0000, 0x0000, 1360, 768, 16, 1, 170, 48, MD_SIS300|MD_SIS315}, {"1360x768x24", {0x4e,0x4e}, 0x0000, 0x0000, 1360, 768, 32, 1, 170, 48, MD_SIS300|MD_SIS315}, - {"1360x768x32", {0x4e,0x4e}, 0x0000, 0x0000, 1360, 768, 32, 1, 170, 48, MD_SIS300|MD_SIS315}, +/*110*/ {"1360x768x32", {0x4e,0x4e}, 0x0000, 0x0000, 1360, 768, 32, 1, 170, 48, MD_SIS300|MD_SIS315}, {"1360x1024x8", {0x67,0x67}, 0x0000, 0x0000, 1360, 1024, 8, 1, 170, 64, MD_SIS300 }, +#define DEFAULT_MODE_1360 112 {"1360x1024x16", {0x6f,0x6f}, 0x0000, 0x0000, 1360, 1024, 16, 1, 170, 64, MD_SIS300 }, {"1360x1024x24", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300 }, -/*110*/ {"1360x1024x32", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300 }, + {"1360x1024x32", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300 }, {"1400x1050x8", {0x26,0x26}, 0x0000, 0x0000, 1400, 1050, 8, 1, 175, 65, MD_SIS315}, {"1400x1050x16", {0x27,0x27}, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65, MD_SIS315}, {"1400x1050x24", {0x28,0x28}, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, MD_SIS315}, {"1400x1050x32", {0x28,0x28}, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, MD_SIS315}, {"1600x1200x8", {0x3c,0x3c}, 0x0130, 0x011c, 1600, 1200, 8, 1, 200, 75, MD_SIS300|MD_SIS315}, - {"1600x1200x16", {0x3d,0x3d}, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315}, +/*120*/ {"1600x1200x16", {0x3d,0x3d}, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315}, {"1600x1200x24", {0x66,0x66}, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315}, {"1600x1200x32", {0x66,0x66}, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315}, {"1680x1050x8", {0x17,0x17}, 0x0000, 0x0000, 1680, 1050, 8, 1, 210, 65, MD_SIS315}, -/*120*/ {"1680x1050x16", {0x18,0x18}, 0x0000, 0x0000, 1680, 1050, 16, 1, 210, 65, MD_SIS315}, + {"1680x1050x16", {0x18,0x18}, 0x0000, 0x0000, 1680, 1050, 16, 1, 210, 65, MD_SIS315}, {"1680x1050x24", {0x19,0x19}, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65, MD_SIS315}, {"1680x1050x32", {0x19,0x19}, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65, MD_SIS315}, {"1920x1080x8", {0x2c,0x2c}, 0x0000, 0x0000, 1920, 1080, 8, 1, 240, 67, MD_SIS315}, {"1920x1080x16", {0x2d,0x2d}, 0x0000, 0x0000, 1920, 1080, 16, 1, 240, 67, MD_SIS315}, {"1920x1080x24", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67, MD_SIS315}, - {"1920x1080x32", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67, MD_SIS315}, +/*130*/ {"1920x1080x32", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67, MD_SIS315}, {"1920x1440x8", {0x68,0x68}, 0x013f, 0x0000, 1920, 1440, 8, 1, 240, 75, MD_SIS300|MD_SIS315}, {"1920x1440x16", {0x69,0x69}, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_SIS300|MD_SIS315}, {"1920x1440x24", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315}, -/*130*/ {"1920x1440x32", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315}, + {"1920x1440x32", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315}, {"2048x1536x8", {0x6c,0x6c}, 0x0000, 0x0000, 2048, 1536, 8, 1, 256, 96, MD_SIS315}, {"2048x1536x16", {0x6d,0x6d}, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96, MD_SIS315}, {"2048x1536x24", {0x6e,0x6e}, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, MD_SIS315}, @@ -313,13 +323,13 @@ static const struct _sisbios_mode { {"\0", {0x00,0x00}, 0, 0, 0, 0, 0, 0, 0} }; -#define SIS_LCD_NUMBER 17 -static const struct _sis_lcd_data { +#define SIS_LCD_NUMBER 18 +static struct _sis_lcd_data { u32 lcdtype; u16 xres; u16 yres; u8 default_mode_idx; -} sis_lcd_data[] = { +} sis_lcd_data[] __devinitdata = { { LCD_640x480, 640, 480, 23 }, { LCD_800x600, 800, 600, 43 }, { LCD_1024x600, 1024, 600, 67 }, @@ -329,34 +339,38 @@ static const struct _sis_lcd_data { { LCD_1280x720, 1280, 720, 83 }, { LCD_1280x768, 1280, 768, 87 }, { LCD_1280x800, 1280, 800, 91 }, - { LCD_1280x960, 1280, 960, 95 }, - { LCD_1280x1024, 1280, 1024, 99 }, - { LCD_1400x1050, 1400, 1050, 111 }, - { LCD_1680x1050, 1680, 1050, 119 }, - { LCD_1600x1200, 1600, 1200, 115 }, - { LCD_640x480_2, 640, 480, 23 }, - { LCD_640x480_3, 640, 480, 23 }, - { LCD_320x480, 320, 480, 9 }, + { LCD_1280x854, 1280, 854, 95 }, + { LCD_1280x960, 1280, 960, 99 }, + { LCD_1280x1024, 1280, 1024, 103 }, + { LCD_1400x1050, 1400, 1050, 115 }, + { LCD_1680x1050, 1680, 1050, 123 }, + { LCD_1600x1200, 1600, 1200, 119 }, + { LCD_320x240_2, 320, 240, 9 }, + { LCD_320x240_3, 320, 240, 9 }, + { LCD_320x240, 320, 240, 9 }, }; /* CR36 evaluation */ -static const USHORT sis300paneltype[] = - { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, - LCD_1280x960, LCD_640x480, LCD_1024x600, LCD_1152x768, - LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, - LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN }; - -static const USHORT sis310paneltype[] = - { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, - LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, - LCD_1152x768, LCD_1400x1050, LCD_1280x768, LCD_1600x1200, - LCD_640x480_2, LCD_640x480_3, LCD_UNKNOWN, LCD_UNKNOWN }; - -static const USHORT sis661paneltype[] = - { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, - LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, - LCD_1152x768, LCD_1400x1050, LCD_1280x768, LCD_1600x1200, - LCD_1280x800, LCD_1680x1050, LCD_1280x720, LCD_UNKNOWN }; +static unsigned short sis300paneltype[] __devinitdata = { + LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_1280x960, LCD_640x480, LCD_1024x600, LCD_1152x768, + LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, + LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN, LCD_UNKNOWN +}; + +static unsigned short sis310paneltype[] __devinitdata = { + LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, + LCD_1152x768, LCD_1400x1050, LCD_1280x768, LCD_1600x1200, + LCD_320x240_2, LCD_320x240_3, LCD_UNKNOWN, LCD_UNKNOWN +}; + +static unsigned short sis661paneltype[] __devinitdata = { + LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, + LCD_1280x854, LCD_1400x1050, LCD_1280x768, LCD_1600x1200, + LCD_1280x800, LCD_1680x1050, LCD_1280x720, LCD_UNKNOWN +}; #define FL_550_DSTN 0x01 #define FL_550_FSTN 0x02 @@ -413,7 +427,6 @@ static const struct _sis_vrate { } sisfb_vrate[] = { {1, 320, 200, 70, TRUE}, {1, 320, 240, 60, TRUE}, - {1, 320, 480, 60, TRUE}, {1, 400, 300, 60, TRUE}, {1, 512, 384, 60, TRUE}, {1, 640, 400, 72, TRUE}, @@ -437,10 +450,11 @@ static const struct _sis_vrate { {4, 1024, 768, 75, FALSE}, {5, 1024, 768, 85, TRUE}, {6, 1024, 768, 100, TRUE}, {7, 1024, 768, 120, TRUE}, {1, 1152, 768, 60, TRUE}, - {1, 1152, 864, 60, TRUE}, {1, 1152, 864, 75, TRUE}, {2, 1152, 864, 84, TRUE}, + {1, 1152, 864, 60, TRUE}, {2, 1152, 864, 75, TRUE}, {3, 1152, 864, 84, TRUE}, {1, 1280, 720, 60, TRUE}, {2, 1280, 720, 75, TRUE}, {3, 1280, 720, 85, TRUE}, {1, 1280, 768, 60, TRUE}, {1, 1280, 800, 60, TRUE}, + {1, 1280, 854, 60, TRUE}, {1, 1280, 960, 60, TRUE}, {2, 1280, 960, 85, TRUE}, {1, 1280, 1024, 43, TRUE}, {2, 1280, 1024, 60, TRUE}, {3, 1280, 1024, 75, TRUE}, {4, 1280, 1024, 85, TRUE}, @@ -459,12 +473,12 @@ static const struct _sis_vrate { {0, 0, 0, 0, FALSE} }; -static const struct _sisfbddcsmodes { +static struct _sisfbddcsmodes { u32 mask; u16 h; u16 v; u32 d; -} sisfb_ddcsmodes[] = { +} sisfb_ddcsmodes[] __devinitdata = { { 0x10000, 67, 75, 108000}, { 0x08000, 48, 72, 50000}, { 0x04000, 46, 75, 49500}, @@ -480,49 +494,49 @@ static const struct _sisfbddcsmodes { { 0x00001, 38, 60, 40000} }; -static const struct _sisfbddcfmodes { +static struct _sisfbddcfmodes { u16 x; u16 y; u16 v; u16 h; u32 d; -} sisfb_ddcfmodes[] = { - { 1280, 1024, 85, 92, 157500}, - { 1600, 1200, 60, 75, 162000}, - { 1600, 1200, 65, 82, 175500}, - { 1600, 1200, 70, 88, 189000}, - { 1600, 1200, 75, 94, 202500}, - { 1600, 1200, 85, 107,229500}, - { 1920, 1440, 60, 90, 234000}, - { 1920, 1440, 75, 113,297000} +} sisfb_ddcfmodes[] __devinitdata = { + { 1280, 1024, 85, 92, 157500}, + { 1600, 1200, 60, 75, 162000}, + { 1600, 1200, 65, 82, 175500}, + { 1600, 1200, 70, 88, 189000}, + { 1600, 1200, 75, 94, 202500}, + { 1600, 1200, 85, 107,229500}, + { 1920, 1440, 60, 90, 234000}, + { 1920, 1440, 75, 113,297000} }; #ifdef CONFIG_FB_SIS_300 static struct _chswtable { - u16 subsysVendor; - u16 subsysCard; - char *vendorName; - char *cardName; + u16 subsysVendor; + u16 subsysCard; + char *vendorName; + char *cardName; } mychswtable[] __devinitdata = { - { 0x1631, 0x1002, "Mitachi", "0x1002" }, + { 0x1631, 0x1002, "Mitachi", "0x1002" }, { 0x1071, 0x7521, "Mitac" , "7521P" }, { 0, 0, "" , "" } }; #endif static struct _customttable { - u16 chipID; - char *biosversion; - char *biosdate; - u32 bioschksum; - u16 biosFootprintAddr[5]; - u8 biosFootprintData[5]; - u16 pcisubsysvendor; - u16 pcisubsyscard; - char *vendorName; - char *cardName; - u32 SpecialID; - char *optionName; + u16 chipID; + char *biosversion; + char *biosdate; + u32 bioschksum; + u16 biosFootprintAddr[5]; + u8 biosFootprintData[5]; + u16 pcisubsysvendor; + u16 pcisubsyscard; + char *vendorName; + char *cardName; + u32 SpecialID; + char *optionName; } mycustomttable[] __devinitdata = { { SIS_630, "2.00.07", "09/27/2002-13:38:25", 0x3240A8, @@ -643,6 +657,13 @@ static struct _customttable { 0, 0, "Generic", "LVDS/Parallel 848x480", CUT_PANEL848, "PANEL848x480" }, + { 4322, "", "", /* never autodetected */ + 0, + { 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0 }, + 0, 0, + "Generic", "LVDS/Parallel 856x480", CUT_PANEL856, "PANEL856x480" + }, { 0, "", "", 0, { 0, 0, 0, 0 }, @@ -652,155 +673,6 @@ static struct _customttable { } }; -static const struct _sis_TV_filter { - u8 filter[9][4]; -} sis_TV_filter[] = { - { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_0 */ - {0x00,0xE0,0x10,0x60}, - {0x00,0xEE,0x10,0x44}, - {0x00,0xF4,0x10,0x38}, - {0xF8,0xF4,0x18,0x38}, - {0xFC,0xFB,0x14,0x2A}, - {0x00,0x00,0x10,0x20}, - {0x00,0x04,0x10,0x18}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_1 */ - {0x00,0xE0,0x10,0x60}, - {0x00,0xEE,0x10,0x44}, - {0x00,0xF4,0x10,0x38}, - {0xF8,0xF4,0x18,0x38}, - {0xFC,0xFB,0x14,0x2A}, - {0x00,0x00,0x10,0x20}, - {0x00,0x04,0x10,0x18}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_2 */ - {0xF5,0xEE,0x1B,0x44}, - {0xF8,0xF4,0x18,0x38}, - {0xEB,0x04,0x25,0x18}, - {0xF1,0x05,0x1F,0x16}, - {0xF6,0x06,0x1A,0x14}, - {0xFA,0x06,0x16,0x14}, - {0x00,0x04,0x10,0x18}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_3 */ - {0xF1,0x04,0x1F,0x18}, - {0xEE,0x0D,0x22,0x06}, - {0xF7,0x06,0x19,0x14}, - {0xF4,0x0B,0x1C,0x0A}, - {0xFA,0x07,0x16,0x12}, - {0xF9,0x0A,0x17,0x0C}, - {0x00,0x07,0x10,0x12}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_4 - 320 */ - {0x00,0xE0,0x10,0x60}, - {0x00,0xEE,0x10,0x44}, - {0x00,0xF4,0x10,0x38}, - {0xF8,0xF4,0x18,0x38}, - {0xFC,0xFB,0x14,0x2A}, - {0x00,0x00,0x10,0x20}, - {0x00,0x04,0x10,0x18}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_5 - 640 */ - {0xF5,0xEE,0x1B,0x44}, - {0xF8,0xF4,0x18,0x38}, - {0xEB,0x04,0x25,0x18}, - {0xF1,0x05,0x1F,0x16}, - {0xF6,0x06,0x1A,0x14}, - {0xFA,0x06,0x16,0x14}, - {0x00,0x04,0x10,0x18}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_6 - 720 */ - {0xEB,0x04,0x25,0x18}, - {0xE7,0x0E,0x29,0x04}, - {0xEE,0x0C,0x22,0x08}, - {0xF6,0x0B,0x1A,0x0A}, - {0xF9,0x0A,0x17,0x0C}, - {0xFC,0x0A,0x14,0x0C}, - {0x00,0x08,0x10,0x10}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_7 - 800 */ - {0xEC,0x02,0x24,0x1C}, - {0xF2,0x04,0x1E,0x18}, - {0xEB,0x15,0x25,0xF6}, - {0xF4,0x10,0x1C,0x00}, - {0xF8,0x0F,0x18,0x02}, - {0x00,0x04,0x10,0x18}, - {0x01,0x06,0x0F,0x14}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* PALFilter_0 */ - {0x00,0xE0,0x10,0x60}, - {0x00,0xEE,0x10,0x44}, - {0x00,0xF4,0x10,0x38}, - {0xF8,0xF4,0x18,0x38}, - {0xFC,0xFB,0x14,0x2A}, - {0x00,0x00,0x10,0x20}, - {0x00,0x04,0x10,0x18}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* PALFilter_1 */ - {0x00,0xE0,0x10,0x60}, - {0x00,0xEE,0x10,0x44}, - {0x00,0xF4,0x10,0x38}, - {0xF8,0xF4,0x18,0x38}, - {0xFC,0xFB,0x14,0x2A}, - {0x00,0x00,0x10,0x20}, - {0x00,0x04,0x10,0x18}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* PALFilter_2 */ - {0xF5,0xEE,0x1B,0x44}, - {0xF8,0xF4,0x18,0x38}, - {0xF1,0xF7,0x01,0x32}, - {0xF5,0xFB,0x1B,0x2A}, - {0xF9,0xFF,0x17,0x22}, - {0xFB,0x01,0x15,0x1E}, - {0x00,0x04,0x10,0x18}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* PALFilter_3 */ - {0xF5,0xFB,0x1B,0x2A}, - {0xEE,0xFE,0x22,0x24}, - {0xF3,0x00,0x1D,0x20}, - {0xF9,0x03,0x17,0x1A}, - {0xFB,0x02,0x14,0x1E}, - {0xFB,0x04,0x15,0x18}, - {0x00,0x06,0x10,0x14}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* PALFilter_4 - 320 */ - {0x00,0xE0,0x10,0x60}, - {0x00,0xEE,0x10,0x44}, - {0x00,0xF4,0x10,0x38}, - {0xF8,0xF4,0x18,0x38}, - {0xFC,0xFB,0x14,0x2A}, - {0x00,0x00,0x10,0x20}, - {0x00,0x04,0x10,0x18}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* PALFilter_5 - 640 */ - {0xF5,0xEE,0x1B,0x44}, - {0xF8,0xF4,0x18,0x38}, - {0xF1,0xF7,0x1F,0x32}, - {0xF5,0xFB,0x1B,0x2A}, - {0xF9,0xFF,0x17,0x22}, - {0xFB,0x01,0x15,0x1E}, - {0x00,0x04,0x10,0x18}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* PALFilter_6 - 720 */ - {0xF5,0xEE,0x1B,0x2A}, - {0xEE,0xFE,0x22,0x24}, - {0xF3,0x00,0x1D,0x20}, - {0xF9,0x03,0x17,0x1A}, - {0xFB,0x02,0x14,0x1E}, - {0xFB,0x04,0x15,0x18}, - {0x00,0x06,0x10,0x14}, - {0xFF,0xFF,0xFF,0xFF} }}, - { {{0x00,0x00,0x00,0x40}, /* PALFilter_7 - 800 */ - {0xF5,0xEE,0x1B,0x44}, - {0xF8,0xF4,0x18,0x38}, - {0xFC,0xFB,0x14,0x2A}, - {0xEB,0x05,0x25,0x16}, - {0xF1,0x05,0x1F,0x16}, - {0xFA,0x07,0x16,0x12}, - {0x00,0x07,0x10,0x12}, - {0xFF,0xFF,0xFF,0xFF} }} -}; - /* ---------------------- Prototypes ------------------------- */ /* Interface used by the world */ @@ -811,145 +683,159 @@ SISINITSTATIC int sisfb_setup(char *options); /* Interface to the low level console driver */ SISINITSTATIC int sisfb_init(void); - /* fbdev routines */ -static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info); +static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -static int sisfb_get_fix(struct fb_fix_screeninfo *fix, - int con, - struct fb_info *info); -static int sisfb_get_var(struct fb_var_screeninfo *var, - int con, - struct fb_info *info); -static int sisfb_set_var(struct fb_var_screeninfo *var, - int con, - struct fb_info *info); -static void sisfb_crtc_to_var(struct sis_video_info *ivideo, - struct fb_var_screeninfo *var); -static int sisfb_get_cmap(struct fb_cmap *cmap, - int kspc, - int con, - struct fb_info *info); -static int sisfb_set_cmap(struct fb_cmap *cmap, - int kspc, - int con, - struct fb_info *info); -static int sisfb_update_var(int con, - struct fb_info *info); -static int sisfb_switch(int con, +static int sisfb_get_fix(struct fb_fix_screeninfo *fix, + int con, + struct fb_info *info); +static int sisfb_get_var(struct fb_var_screeninfo *var, + int con, + struct fb_info *info); +static int sisfb_set_var(struct fb_var_screeninfo *var, + int con, + struct fb_info *info); +static void sisfb_crtc_to_var(struct sis_video_info *ivideo, + struct fb_var_screeninfo *var); +static int sisfb_get_cmap(struct fb_cmap *cmap, + int kspc, + int con, + struct fb_info *info); +static int sisfb_set_cmap(struct fb_cmap *cmap, + int kspc, + int con, + struct fb_info *info); +static int sisfb_update_var(int con, + struct fb_info *info); +static int sisfb_switch(int con, struct fb_info *info); -static void sisfb_blank(int blank, - struct fb_info *info); -static void sisfb_set_disp(int con, - struct fb_var_screeninfo *var, - struct fb_info *info); -static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, - unsigned *blue, unsigned *transp, - struct fb_info *fb_info); -static void sisfb_do_install_cmap(int con, - struct fb_info *info); -static int sisfb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con, - struct fb_info *info); -#endif +static void sisfb_blank(int blank, + struct fb_info *info); +static void sisfb_set_disp(int con, + struct fb_var_screeninfo *var, + struct fb_info *info); +static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *fb_info); +static void sisfb_do_install_cmap(int con, + struct fb_info *info); +static int sisfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info); +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -static int sisfb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, - struct fb_info *info); -static int sisfb_set_par(struct fb_info *info); -static int sisfb_blank(int blank, - struct fb_info *info); -extern void fbcon_sis_fillrect(struct fb_info *info, - const struct fb_fillrect *rect); -extern void fbcon_sis_copyarea(struct fb_info *info, - const struct fb_copyarea *area); -extern int fbcon_sis_sync(struct fb_info *info); +static int sisfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *info); +static int sisfb_set_par(struct fb_info *info); +static int sisfb_blank(int blank, + struct fb_info *info); +extern void fbcon_sis_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +extern void fbcon_sis_copyarea(struct fb_info *info, + const struct fb_copyarea *area); +extern int fbcon_sis_sync(struct fb_info *info); #endif - + /* Internal 2D accelerator functions */ -extern int sisfb_initaccel(struct sis_video_info *ivideo); -extern void sisfb_syncaccel(struct sis_video_info *ivideo); +extern int sisfb_initaccel(struct sis_video_info *ivideo); +extern void sisfb_syncaccel(struct sis_video_info *ivideo); /* Internal general routines */ -static void sisfb_search_mode(char *name, BOOLEAN quiet); -static int sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags); -static u8 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, - int index); -static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *fb_info); -static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, - struct fb_info *info); -static void sisfb_pre_setmode(struct sis_video_info *ivideo); -static void sisfb_post_setmode(struct sis_video_info *ivideo); -static BOOLEAN sisfb_CheckVBRetrace(struct sis_video_info *ivideo); -static BOOLEAN sisfbcheckvretracecrt2(struct sis_video_info *ivideo); -static BOOLEAN sisfbcheckvretracecrt1(struct sis_video_info *ivideo); -static BOOLEAN sisfb_bridgeisslave(struct sis_video_info *ivideo); -static void sisfb_detect_VB_connect(struct sis_video_info *ivideo); -static void sisfb_get_VB_type(struct sis_video_info *ivideo); -static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val); -static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val); +static void sisfb_search_mode(char *name, BOOLEAN quiet); +static int sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags); +static u8 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, + int index); +static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info); +static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, + struct fb_info *info); +static void sisfb_pre_setmode(struct sis_video_info *ivideo); +static void sisfb_post_setmode(struct sis_video_info *ivideo); +static BOOLEAN sisfb_CheckVBRetrace(struct sis_video_info *ivideo); +static BOOLEAN sisfbcheckvretracecrt2(struct sis_video_info *ivideo); +static BOOLEAN sisfbcheckvretracecrt1(struct sis_video_info *ivideo); +static BOOLEAN sisfb_bridgeisslave(struct sis_video_info *ivideo); +static void sisfb_detect_VB_connect(struct sis_video_info *ivideo); +static void sisfb_get_VB_type(struct sis_video_info *ivideo); +static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val); +static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val); +#ifdef CONFIG_FB_SIS_300 +unsigned int sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg); +void sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val); +unsigned int sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg); +#endif +#ifdef CONFIG_FB_SIS_315 +void sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val); +unsigned int sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg); +#endif /* SiS-specific exported functions */ -void sis_malloc(struct sis_memreq *req); -void sis_free(u32 base); +void sis_malloc(struct sis_memreq *req); +void sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req); +void sis_free(u32 base); +void sis_free_new(struct pci_dev *pdev, u32 base); /* Internal heap routines */ -static int sisfb_heap_init(struct sis_video_info *ivideo); -static SIS_OH *sisfb_poh_new_node(void); -static SIS_OH *sisfb_poh_allocate(u32 size); -static void sisfb_delete_node(SIS_OH *poh); -static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh); -static SIS_OH *sisfb_poh_free(u32 base); -static void sisfb_free_node(SIS_OH *poh); - -/* Sensing routines */ -static void SiS_Sense30x(struct sis_video_info *ivideo); -static void SiS_SenseCh(struct sis_video_info *ivideo); +static int sisfb_heap_init(struct sis_video_info *ivideo); +static struct SIS_OH * sisfb_poh_new_node(struct SIS_HEAP *memheap); +static struct SIS_OH * sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size); +static void sisfb_delete_node(struct SIS_OH *poh); +static void sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh); +static struct SIS_OH * sisfb_poh_free(struct SIS_HEAP *memheap, u32 base); +static void sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh); /* Routines from init.c/init301.c */ -extern USHORT SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, - BOOLEAN FSTN, USHORT CustomT, int LCDwith, int LCDheight); -extern USHORT SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth); -extern USHORT SiS_GetModeID_VGA2(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth); - -extern void SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr); -extern BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo, USHORT ModeNo); -extern void SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable); -extern void SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable); - -extern BOOLEAN SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); - -extern BOOLEAN sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceExtension, - unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex); +extern unsigned short SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, BOOLEAN FSTN, unsigned short CustomT, + int LCDwith, int LCDheight, unsigned int VBFlags2); +extern unsigned short SiS_GetModeID_TV(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, unsigned int VBFlags2); +extern unsigned short SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay, + int VDisplay, int Depth, unsigned int VBFlags2); +extern void SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr); +extern BOOLEAN SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); +extern void SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable); +extern void SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable); + +extern BOOLEAN SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr); + +extern BOOLEAN sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, + int *htotal, int *vtotal, unsigned char rateindex); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -extern int sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, - PSIS_HW_INFO HwDeviceExtension, - unsigned char modeno, unsigned char rateindex); -extern int sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceExtension, - unsigned char modeno, unsigned char rateindex, - struct fb_var_screeninfo *var); +extern int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, + unsigned char modeno, unsigned char rateindex); +extern int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno, + unsigned char rateindex, struct fb_var_screeninfo *var); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres, + int yres, struct fb_var_screeninfo *var, BOOLEAN writeres); #endif /* Chrontel TV, DDC and DPMS functions */ -extern USHORT SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx); -extern void SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx); -extern USHORT SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx); -extern void SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx); -extern void SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh); -extern void SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime); -extern void SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo); -extern USHORT SiS_HandleDDC(SiS_Private *SiS_Pr, ULONG VBFlags, int VGAEngine, - USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer); -extern USHORT SiS_ReadDDC1Bit(SiS_Private *SiS_Pr); -extern void SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo); -extern void SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr); -extern void SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo); -extern void SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo); +extern unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg); +extern void SiS_SetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); +extern unsigned short SiS_GetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg); +extern void SiS_SetCH701x(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val); +extern void SiS_SetCH70xxANDOR(struct SiS_Private *SiS_Pr, unsigned short reg, + unsigned char myor, unsigned char myand); +extern void SiS_DDC2Delay(struct SiS_Private *SiS_Pr, unsigned int delaytime); +extern void SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo); +extern unsigned short SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine, + unsigned short adaptnum, unsigned short DDCdatatype, unsigned char *buffer, + unsigned int VBFlags2); +extern unsigned short SiS_ReadDDC1Bit(struct SiS_Private *SiS_Pr); +#ifdef CONFIG_FB_SIS_315 +extern void SiS_Chrontel701xBLOn(struct SiS_Private *SiS_Pr); +extern void SiS_Chrontel701xBLOff(struct SiS_Private *SiS_Pr); +#endif +extern void SiS_SiS30xBLOn(struct SiS_Private *SiS_Pr); +extern void SiS_SiS30xBLOff(struct SiS_Private *SiS_Pr); #endif diff --git a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h index 507bba1a71b5d..831b9f42264bb 100644 --- a/drivers/video/sis/vgatypes.h +++ b/drivers/video/sis/vgatypes.h @@ -3,7 +3,7 @@ /* * General type definitions for universal mode switching modules * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -50,11 +50,10 @@ * */ -#ifndef _VGATYPES_ -#define _VGATYPES_ +#ifndef _VGATYPES_H_ +#define _VGATYPES_H_ -#ifdef LINUX_KERNEL /* We don't want the X driver to depend on kernel source */ -#include <linux/ioctl.h> +#ifdef SIS_LINUX_KERNEL #include <linux/version.h> #endif @@ -66,41 +65,13 @@ #define TRUE 1 #endif -#ifndef NULL -#define NULL 0 -#endif - -#ifndef CHAR -typedef char CHAR; -#endif - -#ifndef SHORT -typedef short SHORT; -#endif - -#ifndef LONG -typedef long LONG; -#endif - -#ifndef UCHAR -typedef unsigned char UCHAR; -#endif - -#ifndef USHORT -typedef unsigned short USHORT; -#endif - -#ifndef ULONG -typedef unsigned long ULONG; -#endif - #ifndef BOOLEAN -typedef unsigned char BOOLEAN; +typedef unsigned int BOOLEAN; #endif #define SISIOMEMTYPE -#ifdef LINUX_KERNEL +#ifdef SIS_LINUX_KERNEL typedef unsigned long SISIOADDRESS; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) #include <linux/types.h> /* Need __iomem */ @@ -109,7 +80,7 @@ typedef unsigned long SISIOADDRESS; #endif #endif -#ifdef LINUX_XF86 +#ifdef SIS_XORG_XF86 #if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0) typedef unsigned long IOADDRESS; typedef unsigned long SISIOADDRESS; @@ -118,7 +89,7 @@ typedef IOADDRESS SISIOADDRESS; #endif #endif -enum _SIS_CHIP_TYPE { +typedef enum _SIS_CHIP_TYPE { SIS_VGALegacy = 0, SIS_530, SIS_OLD, @@ -128,115 +99,27 @@ enum _SIS_CHIP_TYPE { SIS_540, SIS_315H, /* SiS 310 */ SIS_315, - SIS_315PRO, + SIS_315PRO, /* SiS 325 */ SIS_550, SIS_650, SIS_740, SIS_330, SIS_661, SIS_741, - SIS_660, + SIS_670, + SIS_660 = 35, SIS_760, SIS_761, - SIS_340, + SIS_762, + SIS_770, + SIS_340 = 55, + SIS_341, + SIS_342, + XGI_20 = 75, + XGI_40, MAX_SIS_CHIP -}; - -#ifndef SIS_HW_INFO -typedef struct _SIS_HW_INFO SIS_HW_INFO, *PSIS_HW_INFO; - -struct _SIS_HW_INFO -{ -#ifdef LINUX_XF86 - PCITAG PciTag; /* PCI Tag */ -#endif - - UCHAR *pjVirtualRomBase; /* ROM image */ - - BOOLEAN UseROM; /* Use the ROM image if provided */ - -#ifdef LINUX_KERNEL - UCHAR SISIOMEMTYPE *pjVideoMemoryAddress; - /* base virtual memory address */ - /* of Linear VGA memory */ - - ULONG ulVideoMemorySize; /* size, in bytes, of the memory on the board */ -#endif - - SISIOADDRESS ulIOAddress; /* base I/O address of VGA ports (0x3B0; relocated) */ - - UCHAR jChipType; /* Used to Identify SiS Graphics Chip */ - /* defined in the enum "SIS_CHIP_TYPE" (above or sisfb.h) */ +} SIS_CHIP_TYPE; - UCHAR jChipRevision; /* Used to Identify SiS Graphics Chip Revision */ - - BOOLEAN bIntegratedMMEnabled;/* supporting integration MM enable */ -}; -#endif - -/* Addtional IOCTLs for communication sisfb <> X driver */ -/* If changing this, sisfb.h must also be changed (for sisfb) */ - -#ifdef LINUX_XF86 /* We don't want the X driver to depend on the kernel source */ - -/* ioctl for identifying and giving some info (esp. memory heap start) */ -#define SISFB_GET_INFO_SIZE 0x8004f300 -#define SISFB_GET_INFO 0x8000f301 /* Must be patched with result from ..._SIZE at D[29:16] */ -/* deprecated ioctl number (for older versions of sisfb) */ -#define SISFB_GET_INFO_OLD 0x80046ef8 - -/* ioctls for tv parameters (position) */ -#define SISFB_SET_TVPOSOFFSET 0x4004f304 - -/* lock sisfb from register access */ -#define SISFB_SET_LOCK 0x4004f306 - -/* Structure argument for SISFB_GET_INFO ioctl */ -typedef struct _SISFB_INFO sisfb_info, *psisfb_info; - -struct _SISFB_INFO { - CARD32 sisfb_id; /* for identifying sisfb */ -#ifndef SISFB_ID -#define SISFB_ID 0x53495346 /* Identify myself with 'SISF' */ -#endif - CARD32 chip_id; /* PCI ID of detected chip */ - CARD32 memory; /* video memory in KB which sisfb manages */ - CARD32 heapstart; /* heap start (= sisfb "mem" argument) in KB */ - CARD8 fbvidmode; /* current sisfb mode */ - - CARD8 sisfb_version; - CARD8 sisfb_revision; - CARD8 sisfb_patchlevel; - - CARD8 sisfb_caps; /* sisfb's capabilities */ - - CARD32 sisfb_tqlen; /* turbo queue length (in KB) */ - - CARD32 sisfb_pcibus; /* The card's PCI ID */ - CARD32 sisfb_pcislot; - CARD32 sisfb_pcifunc; - - CARD8 sisfb_lcdpdc; - - CARD8 sisfb_lcda; - - CARD32 sisfb_vbflags; - CARD32 sisfb_currentvbflags; - - CARD32 sisfb_scalelcd; - CARD32 sisfb_specialtiming; - - CARD8 sisfb_haveemi; - CARD8 sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33; - CARD8 sisfb_haveemilcd; - - CARD8 sisfb_lcdpdca; - - CARD16 sisfb_tvxpos, sisfb_tvypos; /* Warning: Values + 32 ! */ - - CARD8 reserved[208]; /* for future use */ -}; -#endif #endif diff --git a/drivers/video/sis/vstruct.h b/drivers/video/sis/vstruct.h index d4d55c98bce6e..9ae32923c142d 100644 --- a/drivers/video/sis/vstruct.h +++ b/drivers/video/sis/vstruct.h @@ -3,7 +3,7 @@ /* * General structure definitions for universal mode switching modules * - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * If distributed as part of the Linux kernel, the following license terms * apply: @@ -50,627 +50,514 @@ * */ -#ifndef _VSTRUCT_ -#define _VSTRUCT_ - -typedef struct _SiS_PanelDelayTblStruct -{ - UCHAR timer[2]; -} SiS_PanelDelayTblStruct; - -typedef struct _SiS_LCDDataStruct -{ - USHORT RVBHCMAX; - USHORT RVBHCFACT; - USHORT VGAHT; - USHORT VGAVT; - USHORT LCDHT; - USHORT LCDVT; -} SiS_LCDDataStruct; - -typedef struct _SiS_TVDataStruct -{ - USHORT RVBHCMAX; - USHORT RVBHCFACT; - USHORT VGAHT; - USHORT VGAVT; - USHORT TVHDE; - USHORT TVVDE; - USHORT RVBHRS; - UCHAR FlickerMode; - USHORT HALFRVBHRS; - UCHAR RY1COE; - UCHAR RY2COE; - UCHAR RY3COE; - UCHAR RY4COE; -} SiS_TVDataStruct; - -typedef struct _SiS_LVDSDataStruct -{ - USHORT VGAHT; - USHORT VGAVT; - USHORT LCDHT; - USHORT LCDVT; -} SiS_LVDSDataStruct; - -typedef struct _SiS_LVDSDesStruct -{ - USHORT LCDHDES; - USHORT LCDVDES; -} SiS_LVDSDesStruct; - -typedef struct _SiS_LVDSCRT1DataStruct -{ - UCHAR CR[15]; -} SiS_LVDSCRT1DataStruct; - -typedef struct _SiS_LCDACRT1DataStruct -{ - UCHAR CR[17]; -} SiS_LCDACRT1DataStruct; - -typedef struct _SiS_CHTVRegDataStruct -{ - UCHAR Reg[16]; -} SiS_CHTVRegDataStruct; - -typedef struct _SiS_StStruct -{ - UCHAR St_ModeID; - USHORT St_ModeFlag; - UCHAR St_StTableIndex; - UCHAR St_CRT2CRTC; - UCHAR St_ResInfo; - UCHAR VB_StTVFlickerIndex; - UCHAR VB_StTVEdgeIndex; - UCHAR VB_StTVYFilterIndex; - UCHAR St_PDC; -} SiS_StStruct; - -typedef struct _SiS_VBModeStruct -{ - UCHAR ModeID; - UCHAR VB_TVDelayIndex; - UCHAR VB_TVFlickerIndex; - UCHAR VB_TVPhaseIndex; - UCHAR VB_TVYFilterIndex; - UCHAR VB_LCDDelayIndex; - UCHAR _VB_LCDHIndex; - UCHAR _VB_LCDVIndex; -} SiS_VBModeStruct; - -typedef struct _SiS_StandTableStruct -{ - UCHAR CRT_COLS; - UCHAR ROWS; - UCHAR CHAR_HEIGHT; - USHORT CRT_LEN; - UCHAR SR[4]; - UCHAR MISC; - UCHAR CRTC[0x19]; - UCHAR ATTR[0x14]; - UCHAR GRC[9]; -} SiS_StandTableStruct; - -typedef struct _SiS_ExtStruct -{ - UCHAR Ext_ModeID; - USHORT Ext_ModeFlag; - USHORT Ext_VESAID; - UCHAR Ext_RESINFO; - UCHAR VB_ExtTVFlickerIndex; - UCHAR VB_ExtTVEdgeIndex; - UCHAR VB_ExtTVYFilterIndex; - UCHAR VB_ExtTVYFilterIndexROM661; - UCHAR REFindex; - CHAR ROMMODEIDX661; -} SiS_ExtStruct; - -typedef struct _SiS_Ext2Struct -{ - USHORT Ext_InfoFlag; - UCHAR Ext_CRT1CRTC; - UCHAR Ext_CRTVCLK; - UCHAR Ext_CRT2CRTC; - UCHAR Ext_CRT2CRTC_NS; - UCHAR ModeID; - USHORT XRes; - USHORT YRes; - UCHAR Ext_PDC; -} SiS_Ext2Struct; - -typedef struct _SiS_Part2PortTblStruct -{ - UCHAR CR[12]; -} SiS_Part2PortTblStruct; - -typedef struct _SiS_CRT1TableStruct -{ - UCHAR CR[17]; -} SiS_CRT1TableStruct; - -typedef struct _SiS_MCLKDataStruct -{ - UCHAR SR28,SR29,SR2A; - USHORT CLOCK; -} SiS_MCLKDataStruct; - -typedef struct _SiS_VCLKDataStruct -{ - UCHAR SR2B,SR2C; - USHORT CLOCK; -} SiS_VCLKDataStruct; - -typedef struct _SiS_VBVCLKDataStruct -{ - UCHAR Part4_A,Part4_B; - USHORT CLOCK; -} SiS_VBVCLKDataStruct; - -typedef struct _SiS_StResInfoStruct -{ - USHORT HTotal; - USHORT VTotal; -} SiS_StResInfoStruct; - -typedef struct _SiS_ModeResInfoStruct -{ - USHORT HTotal; - USHORT VTotal; - UCHAR XChar; - UCHAR YChar; -} SiS_ModeResInfoStruct; - - - -typedef UCHAR DRAM4Type[4]; +#ifndef _VSTRUCT_H_ +#define _VSTRUCT_H_ + +struct SiS_PanelDelayTbl { + unsigned char timer[2]; +}; + +struct SiS_LCDData { + unsigned short RVBHCMAX; + unsigned short RVBHCFACT; + unsigned short VGAHT; + unsigned short VGAVT; + unsigned short LCDHT; + unsigned short LCDVT; +}; + +struct SiS_TVData { + unsigned short RVBHCMAX; + unsigned short RVBHCFACT; + unsigned short VGAHT; + unsigned short VGAVT; + unsigned short TVHDE; + unsigned short TVVDE; + unsigned short RVBHRS; + unsigned char FlickerMode; + unsigned short HALFRVBHRS; + unsigned short RVBHRS2; + unsigned char RY1COE; + unsigned char RY2COE; + unsigned char RY3COE; + unsigned char RY4COE; +}; + +struct SiS_LVDSData { + unsigned short VGAHT; + unsigned short VGAVT; + unsigned short LCDHT; + unsigned short LCDVT; +}; + +struct SiS_LVDSDes { + unsigned short LCDHDES; + unsigned short LCDVDES; +}; + +struct SiS_LVDSCRT1Data { + unsigned char CR[15]; +}; + +struct SiS_CHTVRegData { + unsigned char Reg[16]; +}; + +struct SiS_St { + unsigned char St_ModeID; + unsigned short St_ModeFlag; + unsigned char St_StTableIndex; + unsigned char St_CRT2CRTC; + unsigned char St_ResInfo; + unsigned char VB_StTVFlickerIndex; + unsigned char VB_StTVEdgeIndex; + unsigned char VB_StTVYFilterIndex; + unsigned char St_PDC; +}; + +struct SiS_VBMode { + unsigned char ModeID; + unsigned char VB_TVDelayIndex; + unsigned char VB_TVFlickerIndex; + unsigned char VB_TVPhaseIndex; + unsigned char VB_TVYFilterIndex; + unsigned char VB_LCDDelayIndex; + unsigned char _VB_LCDHIndex; + unsigned char _VB_LCDVIndex; +}; + +struct SiS_StandTable_S { + unsigned char CRT_COLS; + unsigned char ROWS; + unsigned char CHAR_HEIGHT; + unsigned short CRT_LEN; + unsigned char SR[4]; + unsigned char MISC; + unsigned char CRTC[0x19]; + unsigned char ATTR[0x14]; + unsigned char GRC[9]; +}; + +struct SiS_Ext { + unsigned char Ext_ModeID; + unsigned short Ext_ModeFlag; + unsigned short Ext_VESAID; + unsigned char Ext_RESINFO; + unsigned char VB_ExtTVFlickerIndex; + unsigned char VB_ExtTVEdgeIndex; + unsigned char VB_ExtTVYFilterIndex; + unsigned char VB_ExtTVYFilterIndexROM661; + unsigned char REFindex; + char ROMMODEIDX661; +}; + +struct SiS_Ext2 { + unsigned short Ext_InfoFlag; + unsigned char Ext_CRT1CRTC; + unsigned char Ext_CRTVCLK; + unsigned char Ext_CRT2CRTC; + unsigned char Ext_CRT2CRTC_NS; + unsigned char ModeID; + unsigned short XRes; + unsigned short YRes; + unsigned char Ext_PDC; + unsigned char Ext_FakeCRT2CRTC; + unsigned char Ext_FakeCRT2Clk; + unsigned char Ext_CRT1CRTC_NORM; + unsigned char Ext_CRTVCLK_NORM; + unsigned char Ext_CRT1CRTC_WIDE; + unsigned char Ext_CRTVCLK_WIDE; +}; + +struct SiS_Part2PortTbl { + unsigned char CR[12]; +}; + +struct SiS_CRT1Table { + unsigned char CR[17]; +}; + +struct SiS_MCLKData { + unsigned char SR28,SR29,SR2A; + unsigned short CLOCK; +}; + +struct SiS_VCLKData { + unsigned char SR2B,SR2C; + unsigned short CLOCK; +}; + +struct SiS_VBVCLKData { + unsigned char Part4_A,Part4_B; + unsigned short CLOCK; +}; + +struct SiS_StResInfo_S { + unsigned short HTotal; + unsigned short VTotal; +}; + +struct SiS_ModeResInfo_S { + unsigned short HTotal; + unsigned short VTotal; + unsigned char XChar; + unsigned char YChar; +}; /* Defines for SiS_CustomT */ /* Never change these for sisfb compatibility */ -#define CUT_NONE 0 -#define CUT_FORCENONE 1 -#define CUT_BARCO1366 2 -#define CUT_BARCO1024 3 -#define CUT_COMPAQ1280 4 -#define CUT_COMPAQ12802 5 -#define CUT_PANEL848 6 -#define CUT_CLEVO1024 7 -#define CUT_CLEVO10242 8 -#define CUT_CLEVO1400 9 -#define CUT_CLEVO14002 10 -#define CUT_UNIWILL1024 11 -#define CUT_ASUSL3000D 12 -#define CUT_UNIWILL10242 13 -#define CUT_ACER1280 14 -#define CUT_COMPAL1400_1 15 -#define CUT_COMPAL1400_2 16 -#define CUT_ASUSA2H_1 17 -#define CUT_ASUSA2H_2 18 - -typedef struct _SiS_Private +#define CUT_NONE 0 +#define CUT_FORCENONE 1 +#define CUT_BARCO1366 2 +#define CUT_BARCO1024 3 +#define CUT_COMPAQ1280 4 +#define CUT_COMPAQ12802 5 +#define CUT_PANEL848 6 +#define CUT_CLEVO1024 7 +#define CUT_CLEVO10242 8 +#define CUT_CLEVO1400 9 +#define CUT_CLEVO14002 10 +#define CUT_UNIWILL1024 11 +#define CUT_ASUSL3000D 12 +#define CUT_UNIWILL10242 13 +#define CUT_ACER1280 14 +#define CUT_COMPAL1400_1 15 +#define CUT_COMPAL1400_2 16 +#define CUT_ASUSA2H_1 17 +#define CUT_ASUSA2H_2 18 +#define CUT_UNKNOWNLCD 19 +#define CUT_AOP8060 20 +#define CUT_PANEL856 21 + +struct SiS_Private { -#ifdef LINUX_KERNEL - SISIOADDRESS RelIO; + unsigned char ChipType; + unsigned char ChipRevision; +#ifdef SIS_XORG_XF86 + PCITAG PciTag; #endif - SISIOADDRESS SiS_P3c4; - SISIOADDRESS SiS_P3d4; - SISIOADDRESS SiS_P3c0; - SISIOADDRESS SiS_P3ce; - SISIOADDRESS SiS_P3c2; - SISIOADDRESS SiS_P3ca; - SISIOADDRESS SiS_P3c6; - SISIOADDRESS SiS_P3c7; - SISIOADDRESS SiS_P3c8; - SISIOADDRESS SiS_P3c9; - SISIOADDRESS SiS_P3cb; - SISIOADDRESS SiS_P3cd; - SISIOADDRESS SiS_P3da; - SISIOADDRESS SiS_Part1Port; - SISIOADDRESS SiS_Part2Port; - SISIOADDRESS SiS_Part3Port; - SISIOADDRESS SiS_Part4Port; - SISIOADDRESS SiS_Part5Port; - SISIOADDRESS SiS_VidCapt; - SISIOADDRESS SiS_VidPlay; - USHORT SiS_IF_DEF_LVDS; - USHORT SiS_IF_DEF_CH70xx; - USHORT SiS_IF_DEF_CONEX; - USHORT SiS_IF_DEF_TRUMPION; - USHORT SiS_IF_DEF_DSTN; - USHORT SiS_IF_DEF_FSTN; - USHORT SiS_SysFlags; - UCHAR SiS_VGAINFO; -#ifdef LINUX_XF86 - USHORT SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4; +#ifdef SIS_LINUX_KERNEL + void *ivideo; #endif - BOOLEAN SiS_UseROM; - BOOLEAN SiS_ROMNew; - BOOLEAN SiS_NeedRomModeData; - BOOLEAN PanelSelfDetected; - int SiS_CHOverScan; - BOOLEAN SiS_CHSOverScan; - BOOLEAN SiS_ChSW; - BOOLEAN SiS_UseLCDA; - int SiS_UseOEM; - ULONG SiS_CustomT; - USHORT SiS_Backup70xx; - BOOLEAN HaveEMI; - BOOLEAN HaveEMILCD; - BOOLEAN OverruleEMI; - UCHAR EMI_30,EMI_31,EMI_32,EMI_33; - USHORT SiS_EMIOffset; - SHORT PDC, PDCA; - UCHAR SiS_MyCR63; - USHORT SiS_CRT1Mode; - USHORT SiS_flag_clearbuffer; - int SiS_RAMType; - UCHAR SiS_ChannelAB; - UCHAR SiS_DataBusWidth; - USHORT SiS_ModeType; - USHORT SiS_VBInfo; - USHORT SiS_TVMode; - USHORT SiS_LCDResInfo; - USHORT SiS_LCDTypeInfo; - USHORT SiS_LCDInfo; - USHORT SiS_LCDInfo661; - USHORT SiS_VBType; - USHORT SiS_VBExtInfo; - USHORT SiS_YPbPr; - USHORT SiS_SelectCRT2Rate; - USHORT SiS_SetFlag; - USHORT SiS_RVBHCFACT; - USHORT SiS_RVBHCMAX; - USHORT SiS_RVBHRS; - USHORT SiS_VGAVT; - USHORT SiS_VGAHT; - USHORT SiS_VT; - USHORT SiS_HT; - USHORT SiS_VGAVDE; - USHORT SiS_VGAHDE; - USHORT SiS_VDE; - USHORT SiS_HDE; - USHORT SiS_NewFlickerMode; - USHORT SiS_RY1COE; - USHORT SiS_RY2COE; - USHORT SiS_RY3COE; - USHORT SiS_RY4COE; - USHORT SiS_LCDHDES; - USHORT SiS_LCDVDES; - USHORT SiS_DDC_Port; - USHORT SiS_DDC_Index; - USHORT SiS_DDC_Data; - USHORT SiS_DDC_NData; - USHORT SiS_DDC_Clk; - USHORT SiS_DDC_NClk; - USHORT SiS_DDC_DeviceAddr; - USHORT SiS_DDC_ReadAddr; - USHORT SiS_DDC_SecAddr; - USHORT SiS_ChrontelInit; - BOOLEAN SiS_SensibleSR11; - USHORT SiS661LCD2TableSize; - - USHORT SiS_PanelMinLVDS; - USHORT SiS_PanelMin301; - - const SiS_StStruct *SiS_SModeIDTable; - const SiS_StandTableStruct *SiS_StandTable; - const SiS_ExtStruct *SiS_EModeIDTable; - const SiS_Ext2Struct *SiS_RefIndex; - const SiS_VBModeStruct *SiS_VBModeIDTable; - const SiS_CRT1TableStruct *SiS_CRT1Table; - const SiS_MCLKDataStruct *SiS_MCLKData_0; - const SiS_MCLKDataStruct *SiS_MCLKData_1; - SiS_VCLKDataStruct *SiS_VCLKData; - SiS_VBVCLKDataStruct *SiS_VBVCLKData; - const SiS_StResInfoStruct *SiS_StResInfo; - const SiS_ModeResInfoStruct *SiS_ModeResInfo; - - const UCHAR *pSiS_OutputSelect; - const UCHAR *pSiS_SoftSetting; - - const DRAM4Type *SiS_SR15; /* pointer : point to array */ -#ifdef LINUX_KERNEL - UCHAR *pSiS_SR07; - const DRAM4Type *SiS_CR40; /* pointer : point to array */ - UCHAR *SiS_CR49; - UCHAR *SiS_SR25; - UCHAR *pSiS_SR1F; - UCHAR *pSiS_SR21; - UCHAR *pSiS_SR22; - UCHAR *pSiS_SR23; - UCHAR *pSiS_SR24; - UCHAR *pSiS_SR31; - UCHAR *pSiS_SR32; - UCHAR *pSiS_SR33; - UCHAR *pSiS_CRT2Data_1_2; - UCHAR *pSiS_CRT2Data_4_D; - UCHAR *pSiS_CRT2Data_4_E; - UCHAR *pSiS_CRT2Data_4_10; - const USHORT *pSiS_RGBSenseData; - const USHORT *pSiS_VideoSenseData; - const USHORT *pSiS_YCSenseData; - const USHORT *pSiS_RGBSenseData2; - const USHORT *pSiS_VideoSenseData2; - const USHORT *pSiS_YCSenseData2; + unsigned char *VirtualRomBase; + BOOLEAN UseROM; +#ifdef SIS_LINUX_KERNEL + unsigned char SISIOMEMTYPE *VideoMemoryAddress; + unsigned int VideoMemorySize; #endif + SISIOADDRESS IOAddress; + SISIOADDRESS IOAddress2; /* For dual chip XGI volari */ - const SiS_PanelDelayTblStruct *SiS_PanelDelayTbl; - const SiS_PanelDelayTblStruct *SiS_PanelDelayTblLVDS; +#ifdef SIS_LINUX_KERNEL + SISIOADDRESS RelIO; +#endif + SISIOADDRESS SiS_P3c4; + SISIOADDRESS SiS_P3d4; + SISIOADDRESS SiS_P3c0; + SISIOADDRESS SiS_P3ce; + SISIOADDRESS SiS_P3c2; + SISIOADDRESS SiS_P3ca; + SISIOADDRESS SiS_P3c6; + SISIOADDRESS SiS_P3c7; + SISIOADDRESS SiS_P3c8; + SISIOADDRESS SiS_P3c9; + SISIOADDRESS SiS_P3cb; + SISIOADDRESS SiS_P3cc; + SISIOADDRESS SiS_P3cd; + SISIOADDRESS SiS_P3da; + SISIOADDRESS SiS_Part1Port; + SISIOADDRESS SiS_Part2Port; + SISIOADDRESS SiS_Part3Port; + SISIOADDRESS SiS_Part4Port; + SISIOADDRESS SiS_Part5Port; + SISIOADDRESS SiS_VidCapt; + SISIOADDRESS SiS_VidPlay; + unsigned short SiS_IF_DEF_LVDS; + unsigned short SiS_IF_DEF_CH70xx; + unsigned short SiS_IF_DEF_CONEX; + unsigned short SiS_IF_DEF_TRUMPION; + unsigned short SiS_IF_DEF_DSTN; + unsigned short SiS_IF_DEF_FSTN; + unsigned short SiS_SysFlags; + unsigned char SiS_VGAINFO; +#ifdef SIS_XORG_XF86 + unsigned short SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4; +#endif + BOOLEAN SiS_UseROM; + BOOLEAN SiS_ROMNew; + BOOLEAN SiS_XGIROM; + BOOLEAN SiS_NeedRomModeData; + BOOLEAN PanelSelfDetected; + BOOLEAN DDCPortMixup; + int SiS_CHOverScan; + BOOLEAN SiS_CHSOverScan; + BOOLEAN SiS_ChSW; + BOOLEAN SiS_UseLCDA; + int SiS_UseOEM; + unsigned int SiS_CustomT; + int SiS_UseWide, SiS_UseWideCRT2; + int SiS_TVBlue; + unsigned short SiS_Backup70xx; + BOOLEAN HaveEMI; + BOOLEAN HaveEMILCD; + BOOLEAN OverruleEMI; + unsigned char EMI_30,EMI_31,EMI_32,EMI_33; + unsigned short SiS_EMIOffset; + unsigned short SiS_PWDOffset; + short PDC, PDCA; + unsigned char SiS_MyCR63; + unsigned short SiS_CRT1Mode; + unsigned short SiS_flag_clearbuffer; + int SiS_RAMType; + unsigned char SiS_ChannelAB; + unsigned char SiS_DataBusWidth; + unsigned short SiS_ModeType; + unsigned short SiS_VBInfo; + unsigned short SiS_TVMode; + unsigned short SiS_LCDResInfo; + unsigned short SiS_LCDTypeInfo; + unsigned short SiS_LCDInfo; + unsigned short SiS_LCDInfo661; + unsigned short SiS_VBType; + unsigned short SiS_VBExtInfo; + unsigned short SiS_YPbPr; + unsigned short SiS_SelectCRT2Rate; + unsigned short SiS_SetFlag; + unsigned short SiS_RVBHCFACT; + unsigned short SiS_RVBHCMAX; + unsigned short SiS_RVBHRS; + unsigned short SiS_RVBHRS2; + unsigned short SiS_VGAVT; + unsigned short SiS_VGAHT; + unsigned short SiS_VT; + unsigned short SiS_HT; + unsigned short SiS_VGAVDE; + unsigned short SiS_VGAHDE; + unsigned short SiS_VDE; + unsigned short SiS_HDE; + unsigned short SiS_NewFlickerMode; + unsigned short SiS_RY1COE; + unsigned short SiS_RY2COE; + unsigned short SiS_RY3COE; + unsigned short SiS_RY4COE; + unsigned short SiS_LCDHDES; + unsigned short SiS_LCDVDES; + unsigned short SiS_DDC_Port; + unsigned short SiS_DDC_Index; + unsigned short SiS_DDC_Data; + unsigned short SiS_DDC_NData; + unsigned short SiS_DDC_Clk; + unsigned short SiS_DDC_NClk; + unsigned short SiS_DDC_DeviceAddr; + unsigned short SiS_DDC_ReadAddr; + unsigned short SiS_DDC_SecAddr; + unsigned short SiS_ChrontelInit; + BOOLEAN SiS_SensibleSR11; + unsigned short SiS661LCD2TableSize; + + unsigned short SiS_PanelMinLVDS; + unsigned short SiS_PanelMin301; + + const struct SiS_St *SiS_SModeIDTable; + const struct SiS_StandTable_S *SiS_StandTable; + const struct SiS_Ext *SiS_EModeIDTable; + const struct SiS_Ext2 *SiS_RefIndex; + const struct SiS_VBMode *SiS_VBModeIDTable; + const struct SiS_CRT1Table *SiS_CRT1Table; + const struct SiS_MCLKData *SiS_MCLKData_0; + const struct SiS_MCLKData *SiS_MCLKData_1; + struct SiS_VCLKData *SiS_VCLKData; + struct SiS_VBVCLKData *SiS_VBVCLKData; + const struct SiS_StResInfo_S *SiS_StResInfo; + const struct SiS_ModeResInfo_S *SiS_ModeResInfo; + + const unsigned char *pSiS_OutputSelect; + const unsigned char *pSiS_SoftSetting; + + const unsigned char *SiS_SR15; + + const struct SiS_PanelDelayTbl *SiS_PanelDelayTbl; + const struct SiS_PanelDelayTbl *SiS_PanelDelayTblLVDS; /* SiS bridge */ - const UCHAR *SiS_NTSCPhase; - const UCHAR *SiS_PALPhase; - const UCHAR *SiS_NTSCPhase2; - const UCHAR *SiS_PALPhase2; - const UCHAR *SiS_PALMPhase; - const UCHAR *SiS_PALNPhase; - const UCHAR *SiS_PALMPhase2; - const UCHAR *SiS_PALNPhase2; - const UCHAR *SiS_SpecialPhase; - const UCHAR *SiS_SpecialPhaseM; - const UCHAR *SiS_SpecialPhaseJ; - const SiS_LCDDataStruct *SiS_ExtLCD1024x768Data; - const SiS_LCDDataStruct *SiS_St2LCD1024x768Data; - const SiS_LCDDataStruct *SiS_LCD1280x720Data; - const SiS_LCDDataStruct *SiS_StLCD1280x768_2Data; - const SiS_LCDDataStruct *SiS_ExtLCD1280x768_2Data; - const SiS_LCDDataStruct *SiS_LCD1280x800Data; - const SiS_LCDDataStruct *SiS_LCD1280x800_2Data; - const SiS_LCDDataStruct *SiS_LCD1280x960Data; - const SiS_LCDDataStruct *SiS_ExtLCD1280x1024Data; - const SiS_LCDDataStruct *SiS_St2LCD1280x1024Data; - const SiS_LCDDataStruct *SiS_StLCD1400x1050Data; - const SiS_LCDDataStruct *SiS_ExtLCD1400x1050Data; - const SiS_LCDDataStruct *SiS_StLCD1600x1200Data; - const SiS_LCDDataStruct *SiS_ExtLCD1600x1200Data; - const SiS_LCDDataStruct *SiS_LCD1680x1050Data; - const SiS_LCDDataStruct *SiS_NoScaleData; - const SiS_TVDataStruct *SiS_StPALData; - const SiS_TVDataStruct *SiS_ExtPALData; - const SiS_TVDataStruct *SiS_StNTSCData; - const SiS_TVDataStruct *SiS_ExtNTSCData; - const SiS_TVDataStruct *SiS_St1HiTVData; - const SiS_TVDataStruct *SiS_St2HiTVData; - const SiS_TVDataStruct *SiS_ExtHiTVData; - const SiS_TVDataStruct *SiS_St525iData; - const SiS_TVDataStruct *SiS_St525pData; - const SiS_TVDataStruct *SiS_St750pData; - const SiS_TVDataStruct *SiS_Ext525iData; - const SiS_TVDataStruct *SiS_Ext525pData; - const SiS_TVDataStruct *SiS_Ext750pData; - const UCHAR *SiS_NTSCTiming; - const UCHAR *SiS_PALTiming; - const UCHAR *SiS_HiTVExtTiming; - const UCHAR *SiS_HiTVSt1Timing; - const UCHAR *SiS_HiTVSt2Timing; - const UCHAR *SiS_HiTVGroup3Data; - const UCHAR *SiS_HiTVGroup3Simu; + const struct SiS_LCDData *SiS_ExtLCD1024x768Data; + const struct SiS_LCDData *SiS_St2LCD1024x768Data; + const struct SiS_LCDData *SiS_LCD1280x720Data; + const struct SiS_LCDData *SiS_StLCD1280x768_2Data; + const struct SiS_LCDData *SiS_ExtLCD1280x768_2Data; + const struct SiS_LCDData *SiS_LCD1280x800Data; + const struct SiS_LCDData *SiS_LCD1280x800_2Data; + const struct SiS_LCDData *SiS_LCD1280x854Data; + const struct SiS_LCDData *SiS_LCD1280x960Data; + const struct SiS_LCDData *SiS_ExtLCD1280x1024Data; + const struct SiS_LCDData *SiS_St2LCD1280x1024Data; + const struct SiS_LCDData *SiS_StLCD1400x1050Data; + const struct SiS_LCDData *SiS_ExtLCD1400x1050Data; + const struct SiS_LCDData *SiS_StLCD1600x1200Data; + const struct SiS_LCDData *SiS_ExtLCD1600x1200Data; + const struct SiS_LCDData *SiS_LCD1680x1050Data; + const struct SiS_LCDData *SiS_NoScaleData; + const struct SiS_TVData *SiS_StPALData; + const struct SiS_TVData *SiS_ExtPALData; + const struct SiS_TVData *SiS_StNTSCData; + const struct SiS_TVData *SiS_ExtNTSCData; + const struct SiS_TVData *SiS_St1HiTVData; + const struct SiS_TVData *SiS_St2HiTVData; + const struct SiS_TVData *SiS_ExtHiTVData; + const struct SiS_TVData *SiS_St525iData; + const struct SiS_TVData *SiS_St525pData; + const struct SiS_TVData *SiS_St750pData; + const struct SiS_TVData *SiS_Ext525iData; + const struct SiS_TVData *SiS_Ext525pData; + const struct SiS_TVData *SiS_Ext750pData; + const unsigned char *SiS_NTSCTiming; + const unsigned char *SiS_PALTiming; + const unsigned char *SiS_HiTVExtTiming; + const unsigned char *SiS_HiTVSt1Timing; + const unsigned char *SiS_HiTVSt2Timing; + const unsigned char *SiS_HiTVGroup3Data; + const unsigned char *SiS_HiTVGroup3Simu; #if 0 - const UCHAR *SiS_HiTVTextTiming; - const UCHAR *SiS_HiTVGroup3Text; + const unsigned char *SiS_HiTVTextTiming; + const unsigned char *SiS_HiTVGroup3Text; #endif - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_1; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_1; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_2; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_2; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_3; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_3; + const struct SiS_Part2PortTbl *SiS_CRT2Part2_1024x768_1; + const struct SiS_Part2PortTbl *SiS_CRT2Part2_1024x768_2; + const struct SiS_Part2PortTbl *SiS_CRT2Part2_1024x768_3; /* LVDS, Chrontel */ - const SiS_LVDSDataStruct *SiS_LVDS800x600Data_1; - const SiS_LVDSDataStruct *SiS_LVDS800x600Data_2; - const SiS_LVDSDataStruct *SiS_LVDS1024x768Data_1; - const SiS_LVDSDataStruct *SiS_LVDS1024x768Data_2; - const SiS_LVDSDataStruct *SiS_LVDS1280x1024Data_1; - const SiS_LVDSDataStruct *SiS_LVDS1280x1024Data_2; - const SiS_LVDSDataStruct *SiS_LVDS1280x960Data_1; - const SiS_LVDSDataStruct *SiS_LVDS1280x960Data_2; - const SiS_LVDSDataStruct *SiS_LVDS1400x1050Data_1; - const SiS_LVDSDataStruct *SiS_LVDS1400x1050Data_2; - const SiS_LVDSDataStruct *SiS_LVDS1600x1200Data_1; - const SiS_LVDSDataStruct *SiS_LVDS1600x1200Data_2; - const SiS_LVDSDataStruct *SiS_LVDS1280x768Data_1; - const SiS_LVDSDataStruct *SiS_LVDS1280x768Data_2; - const SiS_LVDSDataStruct *SiS_LVDS1024x600Data_1; - const SiS_LVDSDataStruct *SiS_LVDS1024x600Data_2; - const SiS_LVDSDataStruct *SiS_LVDS1152x768Data_1; - const SiS_LVDSDataStruct *SiS_LVDS1152x768Data_2; - const SiS_LVDSDataStruct *SiS_LVDS640x480Data_1; - const SiS_LVDSDataStruct *SiS_LVDS640x480Data_2; - const SiS_LVDSDataStruct *SiS_LVDS320x480Data_1; - const SiS_LVDSDataStruct *SiS_LVDSXXXxXXXData_1; - const SiS_LVDSDataStruct *SiS_LVDSBARCO1366Data_1; - const SiS_LVDSDataStruct *SiS_LVDSBARCO1366Data_2; - const SiS_LVDSDataStruct *SiS_LVDSBARCO1024Data_1; - const SiS_LVDSDataStruct *SiS_LVDSBARCO1024Data_2; - const SiS_LVDSDataStruct *SiS_LVDS848x480Data_1; - const SiS_LVDSDataStruct *SiS_LVDS848x480Data_2; - const SiS_LVDSDataStruct *SiS_CHTVUNTSCData; - const SiS_LVDSDataStruct *SiS_CHTVONTSCData; - const SiS_LVDSDataStruct *SiS_CHTVUPALData; - const SiS_LVDSDataStruct *SiS_CHTVOPALData; - const SiS_LVDSDataStruct *SiS_CHTVUPALMData; - const SiS_LVDSDataStruct *SiS_CHTVOPALMData; - const SiS_LVDSDataStruct *SiS_CHTVUPALNData; - const SiS_LVDSDataStruct *SiS_CHTVOPALNData; - const SiS_LVDSDataStruct *SiS_CHTVSOPALData; - - const SiS_LVDSDesStruct *SiS_PanelType00_1; - const SiS_LVDSDesStruct *SiS_PanelType01_1; - const SiS_LVDSDesStruct *SiS_PanelType02_1; - const SiS_LVDSDesStruct *SiS_PanelType03_1; - const SiS_LVDSDesStruct *SiS_PanelType04_1; - const SiS_LVDSDesStruct *SiS_PanelType05_1; - const SiS_LVDSDesStruct *SiS_PanelType06_1; - const SiS_LVDSDesStruct *SiS_PanelType07_1; - const SiS_LVDSDesStruct *SiS_PanelType08_1; - const SiS_LVDSDesStruct *SiS_PanelType09_1; - const SiS_LVDSDesStruct *SiS_PanelType0a_1; - const SiS_LVDSDesStruct *SiS_PanelType0b_1; - const SiS_LVDSDesStruct *SiS_PanelType0c_1; - const SiS_LVDSDesStruct *SiS_PanelType0d_1; - const SiS_LVDSDesStruct *SiS_PanelType0e_1; - const SiS_LVDSDesStruct *SiS_PanelType0f_1; - const SiS_LVDSDesStruct *SiS_PanelTypeNS_1; - const SiS_LVDSDesStruct *SiS_PanelType00_2; - const SiS_LVDSDesStruct *SiS_PanelType01_2; - const SiS_LVDSDesStruct *SiS_PanelType02_2; - const SiS_LVDSDesStruct *SiS_PanelType03_2; - const SiS_LVDSDesStruct *SiS_PanelType04_2; - const SiS_LVDSDesStruct *SiS_PanelType05_2; - const SiS_LVDSDesStruct *SiS_PanelType06_2; - const SiS_LVDSDesStruct *SiS_PanelType07_2; - const SiS_LVDSDesStruct *SiS_PanelType08_2; - const SiS_LVDSDesStruct *SiS_PanelType09_2; - const SiS_LVDSDesStruct *SiS_PanelType0a_2; - const SiS_LVDSDesStruct *SiS_PanelType0b_2; - const SiS_LVDSDesStruct *SiS_PanelType0c_2; - const SiS_LVDSDesStruct *SiS_PanelType0d_2; - const SiS_LVDSDesStruct *SiS_PanelType0e_2; - const SiS_LVDSDesStruct *SiS_PanelType0f_2; - const SiS_LVDSDesStruct *SiS_PanelTypeNS_2; - const SiS_LVDSDesStruct *SiS_CHTVUNTSCDesData; - const SiS_LVDSDesStruct *SiS_CHTVONTSCDesData; - const SiS_LVDSDesStruct *SiS_CHTVUPALDesData; - const SiS_LVDSDesStruct *SiS_CHTVOPALDesData; - - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_1; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_1; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_1; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11400x1050_1; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x768_1; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x600_1; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11152x768_1; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11600x1200_1; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_1_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_1_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_1_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11400x1050_1_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x768_1_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x600_1_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11152x768_1_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11600x1200_1_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_2; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_2; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_2; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11400x1050_2; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x768_2; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x600_2; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11152x768_2; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11600x1200_2; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_2_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_2_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_2_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11400x1050_2_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x768_2_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x600_2_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11152x768_2_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11600x1200_2_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1XXXxXXX_1; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1XXXxXXX_1_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_1; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_1_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_2; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_2_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_3; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_3_H; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1320x480_1; - const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1UNTSC; - const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1ONTSC; - const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1UPAL; - const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1OPAL; - const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1SOPAL; - - const SiS_CHTVRegDataStruct *SiS_CHTVReg_UNTSC; - const SiS_CHTVRegDataStruct *SiS_CHTVReg_ONTSC; - const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPAL; - const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPAL; - const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPALM; - const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPALM; - const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPALN; - const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPALN; - const SiS_CHTVRegDataStruct *SiS_CHTVReg_SOPAL; - - const UCHAR *SiS_CHTVVCLKUNTSC; - const UCHAR *SiS_CHTVVCLKONTSC; - const UCHAR *SiS_CHTVVCLKUPAL; - const UCHAR *SiS_CHTVVCLKOPAL; - const UCHAR *SiS_CHTVVCLKUPALM; - const UCHAR *SiS_CHTVVCLKOPALM; - const UCHAR *SiS_CHTVVCLKUPALN; - const UCHAR *SiS_CHTVVCLKOPALN; - const UCHAR *SiS_CHTVVCLKSOPAL; - - USHORT PanelXRes, PanelHT; - USHORT PanelYRes, PanelVT; - USHORT PanelHRS, PanelHRE; - USHORT PanelVRS, PanelVRE; - USHORT PanelVCLKIdx300; - USHORT PanelVCLKIdx315; - - BOOLEAN UseCustomMode; - BOOLEAN CRT1UsesCustomMode; - USHORT CHDisplay; - USHORT CHSyncStart; - USHORT CHSyncEnd; - USHORT CHTotal; - USHORT CHBlankStart; - USHORT CHBlankEnd; - USHORT CVDisplay; - USHORT CVSyncStart; - USHORT CVSyncEnd; - USHORT CVTotal; - USHORT CVBlankStart; - USHORT CVBlankEnd; - ULONG CDClock; - ULONG CFlags; - UCHAR CCRT1CRTC[17]; - UCHAR CSR2B; - UCHAR CSR2C; - USHORT CSRClock; - USHORT CSRClock_CRT1; - USHORT CModeFlag; - USHORT CModeFlag_CRT1; - USHORT CInfoFlag; - - int LVDSHL; - - BOOLEAN Backup; - UCHAR Backup_Mode; - UCHAR Backup_14; - UCHAR Backup_15; - UCHAR Backup_16; - UCHAR Backup_17; - UCHAR Backup_18; - UCHAR Backup_19; - UCHAR Backup_1a; - UCHAR Backup_1b; - UCHAR Backup_1c; - UCHAR Backup_1d; - - int UsePanelScaler; - int CenterScreen; - - USHORT CP_Vendor, CP_Product; - BOOLEAN CP_HaveCustomData; - int CP_PreferredX, CP_PreferredY, CP_PreferredIndex; - int CP_MaxX, CP_MaxY, CP_MaxClock; - UCHAR CP_PrefSR2B, CP_PrefSR2C; - USHORT CP_PrefClock; - BOOLEAN CP_Supports64048075; - int CP_HDisplay[7], CP_VDisplay[7]; /* For Custom LCD panel dimensions */ - int CP_HTotal[7], CP_VTotal[7]; - int CP_HSyncStart[7], CP_VSyncStart[7]; - int CP_HSyncEnd[7], CP_VSyncEnd[7]; - int CP_HBlankStart[7], CP_VBlankStart[7]; - int CP_HBlankEnd[7], CP_VBlankEnd[7]; - int CP_Clock[7]; - BOOLEAN CP_DataValid[7]; - BOOLEAN CP_HSync_P[7], CP_VSync_P[7], CP_SyncValid[7]; -} SiS_Private; + const struct SiS_LVDSData *SiS_LVDS320x240Data_1; + const struct SiS_LVDSData *SiS_LVDS320x240Data_2; + const struct SiS_LVDSData *SiS_LVDS640x480Data_1; + const struct SiS_LVDSData *SiS_LVDS800x600Data_1; + const struct SiS_LVDSData *SiS_LVDS1024x600Data_1; + const struct SiS_LVDSData *SiS_LVDS1024x768Data_1; + const struct SiS_LVDSData *SiS_LVDSBARCO1366Data_1; + const struct SiS_LVDSData *SiS_LVDSBARCO1366Data_2; + const struct SiS_LVDSData *SiS_LVDSBARCO1024Data_1; + const struct SiS_LVDSData *SiS_LVDS848x480Data_1; + const struct SiS_LVDSData *SiS_LVDS848x480Data_2; + const struct SiS_LVDSData *SiS_CHTVUNTSCData; + const struct SiS_LVDSData *SiS_CHTVONTSCData; + const struct SiS_LVDSData *SiS_CHTVUPALData; + const struct SiS_LVDSData *SiS_CHTVOPALData; + const struct SiS_LVDSData *SiS_CHTVUPALMData; + const struct SiS_LVDSData *SiS_CHTVOPALMData; + const struct SiS_LVDSData *SiS_CHTVUPALNData; + const struct SiS_LVDSData *SiS_CHTVOPALNData; + const struct SiS_LVDSData *SiS_CHTVSOPALData; + + const struct SiS_LVDSDes *SiS_PanelType04_1a; + const struct SiS_LVDSDes *SiS_PanelType04_2a; + const struct SiS_LVDSDes *SiS_PanelType04_1b; + const struct SiS_LVDSDes *SiS_PanelType04_2b; + + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1320x240_1; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1320x240_2; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1320x240_2_H; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1320x240_3; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1320x240_3_H; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1640x480_1; + const struct SiS_LVDSCRT1Data *SiS_LVDSCRT1640x480_1_H; + const struct SiS_LVDSCRT1Data *SiS_CHTVCRT1UNTSC; + const struct SiS_LVDSCRT1Data *SiS_CHTVCRT1ONTSC; + const struct SiS_LVDSCRT1Data *SiS_CHTVCRT1UPAL; + const struct SiS_LVDSCRT1Data *SiS_CHTVCRT1OPAL; + const struct SiS_LVDSCRT1Data *SiS_CHTVCRT1SOPAL; + + const struct SiS_CHTVRegData *SiS_CHTVReg_UNTSC; + const struct SiS_CHTVRegData *SiS_CHTVReg_ONTSC; + const struct SiS_CHTVRegData *SiS_CHTVReg_UPAL; + const struct SiS_CHTVRegData *SiS_CHTVReg_OPAL; + const struct SiS_CHTVRegData *SiS_CHTVReg_UPALM; + const struct SiS_CHTVRegData *SiS_CHTVReg_OPALM; + const struct SiS_CHTVRegData *SiS_CHTVReg_UPALN; + const struct SiS_CHTVRegData *SiS_CHTVReg_OPALN; + const struct SiS_CHTVRegData *SiS_CHTVReg_SOPAL; + + const unsigned char *SiS_CHTVVCLKUNTSC; + const unsigned char *SiS_CHTVVCLKONTSC; + const unsigned char *SiS_CHTVVCLKUPAL; + const unsigned char *SiS_CHTVVCLKOPAL; + const unsigned char *SiS_CHTVVCLKUPALM; + const unsigned char *SiS_CHTVVCLKOPALM; + const unsigned char *SiS_CHTVVCLKUPALN; + const unsigned char *SiS_CHTVVCLKOPALN; + const unsigned char *SiS_CHTVVCLKSOPAL; + + unsigned short PanelXRes, PanelHT; + unsigned short PanelYRes, PanelVT; + unsigned short PanelHRS, PanelHRE; + unsigned short PanelVRS, PanelVRE; + unsigned short PanelVCLKIdx300; + unsigned short PanelVCLKIdx315; + BOOLEAN Alternate1600x1200; + + BOOLEAN UseCustomMode; + BOOLEAN CRT1UsesCustomMode; + unsigned short CHDisplay; + unsigned short CHSyncStart; + unsigned short CHSyncEnd; + unsigned short CHTotal; + unsigned short CHBlankStart; + unsigned short CHBlankEnd; + unsigned short CVDisplay; + unsigned short CVSyncStart; + unsigned short CVSyncEnd; + unsigned short CVTotal; + unsigned short CVBlankStart; + unsigned short CVBlankEnd; + unsigned int CDClock; + unsigned int CFlags; + unsigned char CCRT1CRTC[17]; + unsigned char CSR2B; + unsigned char CSR2C; + unsigned short CSRClock; + unsigned short CSRClock_CRT1; + unsigned short CModeFlag; + unsigned short CModeFlag_CRT1; + unsigned short CInfoFlag; + + int LVDSHL; + + BOOLEAN Backup; + unsigned char Backup_Mode; + unsigned char Backup_14; + unsigned char Backup_15; + unsigned char Backup_16; + unsigned char Backup_17; + unsigned char Backup_18; + unsigned char Backup_19; + unsigned char Backup_1a; + unsigned char Backup_1b; + unsigned char Backup_1c; + unsigned char Backup_1d; + + unsigned char Init_P4_0E; + + int UsePanelScaler; + int CenterScreen; + + unsigned short CP_Vendor, CP_Product; + BOOLEAN CP_HaveCustomData; + int CP_PreferredX, CP_PreferredY, CP_PreferredIndex; + int CP_MaxX, CP_MaxY, CP_MaxClock; + unsigned char CP_PrefSR2B, CP_PrefSR2C; + unsigned short CP_PrefClock; + BOOLEAN CP_Supports64048075; + int CP_HDisplay[7], CP_VDisplay[7]; /* For Custom LCD panel dimensions */ + int CP_HTotal[7], CP_VTotal[7]; + int CP_HSyncStart[7], CP_VSyncStart[7]; + int CP_HSyncEnd[7], CP_VSyncEnd[7]; + int CP_HBlankStart[7], CP_VBlankStart[7]; + int CP_HBlankEnd[7], CP_VBlankEnd[7]; + int CP_Clock[7]; + BOOLEAN CP_DataValid[7]; + BOOLEAN CP_HSync_P[7], CP_VSync_P[7], CP_SyncValid[7]; +}; #endif diff --git a/include/linux/fb.h b/include/linux/fb.h index c71a7162e0983..34814a0b2378f 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -107,6 +107,8 @@ #define FB_ACCEL_NV_20 44 /* nVidia Arch 20 */ #define FB_ACCEL_NV_30 45 /* nVidia Arch 30 */ #define FB_ACCEL_NV_40 46 /* nVidia Arch 40 */ +#define FB_ACCEL_XGI_VOLARI_V 47 /* XGI Volari V3XT, V5, V8 */ +#define FB_ACCEL_XGI_VOLARI_Z 48 /* XGI Volari Z7 */ #define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */ #define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */ #define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */ diff --git a/include/video/sisfb.h b/include/video/sisfb.h index 136bf791643d1..e402eb5b3c7a2 100644 --- a/include/video/sisfb.h +++ b/include/video/sisfb.h @@ -1,5 +1,7 @@ /* - * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria. + * sisfb.h - definitions for the SiS framebuffer driver + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria. * * 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 @@ -16,8 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ -#ifndef _LINUX_SISFB -#define _LINUX_SISFB +#ifndef _LINUX_SISFB_H_ +#define _LINUX_SISFB_H_ #include <asm/ioctl.h> #include <asm/types.h> @@ -26,47 +28,35 @@ /* PUBLIC */ /**********************************************/ -/* vbflags */ -#define CRT2_DEFAULT 0x00000001 -#define CRT2_LCD 0x00000002 /* TW: Never change the order of the CRT2_XXX entries */ -#define CRT2_TV 0x00000004 /* (see SISCycleCRT2Type()) */ -#define CRT2_VGA 0x00000008 -#define TV_NTSC 0x00000010 -#define TV_PAL 0x00000020 -#define TV_HIVISION 0x00000040 -#define TV_YPBPR 0x00000080 -#define TV_AVIDEO 0x00000100 -#define TV_SVIDEO 0x00000200 -#define TV_SCART 0x00000400 -#define VB_CONEXANT 0x00000800 /* 661 series only */ -#define VB_TRUMPION VB_CONEXANT /* 300 series only */ -#define TV_PALM 0x00001000 -#define TV_PALN 0x00002000 +/* vbflags, public (others in sis.h) */ +#define CRT2_DEFAULT 0x00000001 +#define CRT2_LCD 0x00000002 +#define CRT2_TV 0x00000004 +#define CRT2_VGA 0x00000008 +#define TV_NTSC 0x00000010 +#define TV_PAL 0x00000020 +#define TV_HIVISION 0x00000040 +#define TV_YPBPR 0x00000080 +#define TV_AVIDEO 0x00000100 +#define TV_SVIDEO 0x00000200 +#define TV_SCART 0x00000400 +#define TV_PALM 0x00001000 +#define TV_PALN 0x00002000 #define TV_NTSCJ 0x00001000 -#define VB_302ELV 0x00004000 -#define TV_CHSCART 0x00008000 -#define TV_CHYPBPR525I 0x00010000 +#define TV_CHSCART 0x00008000 +#define TV_CHYPBPR525I 0x00010000 #define CRT1_VGA 0x00000000 #define CRT1_LCDA 0x00020000 #define VGA2_CONNECTED 0x00040000 -#define VB_DISPTYPE_CRT1 0x00080000 /* CRT1 connected and used */ -#define VB_301 0x00100000 /* Video bridge type */ -#define VB_301B 0x00200000 -#define VB_302B 0x00400000 -#define VB_30xBDH 0x00800000 /* 30xB DH version (w/o LCD support) */ -#define VB_LVDS 0x01000000 -#define VB_CHRONTEL 0x02000000 -#define VB_301LV 0x04000000 -#define VB_302LV 0x08000000 -#define VB_301C 0x10000000 -#define VB_SINGLE_MODE 0x20000000 /* CRT1 or CRT2; determined by DISPTYPE_CRTx */ -#define VB_MIRROR_MODE 0x40000000 /* CRT1 + CRT2 identical (mirror mode) */ -#define VB_DUALVIEW_MODE 0x80000000 /* CRT1 + CRT2 independent (dual head mode) */ +#define VB_DISPTYPE_CRT1 0x00080000 /* CRT1 connected and used */ +#define VB_SINGLE_MODE 0x20000000 /* CRT1 or CRT2; determined by DISPTYPE_CRTx */ +#define VB_MIRROR_MODE 0x40000000 /* CRT1 + CRT2 identical (mirror mode) */ +#define VB_DUALVIEW_MODE 0x80000000 /* CRT1 + CRT2 independent (dual head mode) */ /* Aliases: */ #define CRT2_ENABLE (CRT2_LCD | CRT2_TV | CRT2_VGA) -#define TV_STANDARD (TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ) -#define TV_INTERFACE (TV_AVIDEO|TV_SVIDEO|TV_SCART|TV_HIVISION|TV_YPBPR|TV_CHSCART|TV_CHYPBPR525I) +#define TV_STANDARD (TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ) +#define TV_INTERFACE (TV_AVIDEO|TV_SVIDEO|TV_SCART|TV_HIVISION|TV_YPBPR|TV_CHSCART|TV_CHYPBPR525I) /* Only if TV_YPBPR is set: */ #define TV_YPBPR525I TV_NTSC @@ -75,89 +65,118 @@ #define TV_YPBPR1080I TV_PALN #define TV_YPBPRALL (TV_YPBPR525I | TV_YPBPR525P | TV_YPBPR750P | TV_YPBPR1080I) -#define VB_SISBRIDGE (VB_301|VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV|VB_302ELV) -#define VB_SISTVBRIDGE (VB_301|VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV) -#define VB_VIDEOBRIDGE (VB_SISBRIDGE | VB_LVDS | VB_CHRONTEL | VB_CONEXANT) - #define VB_DISPTYPE_DISP2 CRT2_ENABLE #define VB_DISPTYPE_CRT2 CRT2_ENABLE #define VB_DISPTYPE_DISP1 VB_DISPTYPE_CRT1 #define VB_DISPMODE_SINGLE VB_SINGLE_MODE #define VB_DISPMODE_MIRROR VB_MIRROR_MODE #define VB_DISPMODE_DUAL VB_DUALVIEW_MODE -#define VB_DISPLAY_MODE (SINGLE_MODE | MIRROR_MODE | DUALVIEW_MODE) +#define VB_DISPLAY_MODE (SINGLE_MODE | MIRROR_MODE | DUALVIEW_MODE) /* Structure argument for SISFB_GET_INFO ioctl */ -typedef struct _SISFB_INFO sisfb_info, *psisfb_info; - -struct _SISFB_INFO { - __u32 sisfb_id; /* for identifying sisfb */ +struct sisfb_info { + __u32 sisfb_id; /* for identifying sisfb */ #ifndef SISFB_ID #define SISFB_ID 0x53495346 /* Identify myself with 'SISF' */ #endif - __u32 chip_id; /* PCI-ID of detected chip */ - __u32 memory; /* video memory in KB which sisfb manages */ - __u32 heapstart; /* heap start (= sisfb "mem" argument) in KB */ + __u32 chip_id; /* PCI-ID of detected chip */ + __u32 memory; /* total video memory in KB */ + __u32 heapstart; /* heap start offset in KB */ __u8 fbvidmode; /* current sisfb mode */ - __u8 sisfb_version; - __u8 sisfb_revision; - __u8 sisfb_patchlevel; + __u8 sisfb_version; + __u8 sisfb_revision; + __u8 sisfb_patchlevel; - __u8 sisfb_caps; /* sisfb capabilities */ + __u8 sisfb_caps; /* sisfb capabilities */ __u32 sisfb_tqlen; /* turbo queue length (in KB) */ - __u32 sisfb_pcibus; /* The card's PCI ID */ - __u32 sisfb_pcislot; - __u32 sisfb_pcifunc; + __u32 sisfb_pcibus; /* The card's PCI ID */ + __u32 sisfb_pcislot; + __u32 sisfb_pcifunc; + + __u8 sisfb_lcdpdc; /* PanelDelayCompensation */ + + __u8 sisfb_lcda; /* Detected status of LCDA for low res/text modes */ + + __u32 sisfb_vbflags; + __u32 sisfb_currentvbflags; + + __u32 sisfb_scalelcd; + __u32 sisfb_specialtiming; + + __u8 sisfb_haveemi; + __u8 sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33; + __u8 sisfb_haveemilcd; - __u8 sisfb_lcdpdc; /* PanelDelayCompensation */ + __u8 sisfb_lcdpdca; /* PanelDelayCompensation for LCD-via-CRT1 */ - __u8 sisfb_lcda; /* Detected status of LCDA for low res/text modes */ + __u16 sisfb_tvxpos, sisfb_tvypos; /* Warning: Values + 32 ! */ - __u32 sisfb_vbflags; - __u32 sisfb_currentvbflags; + __u32 sisfb_heapsize; /* heap size (in KB) */ + __u32 sisfb_videooffset; /* Offset of viewport in video memory (in bytes) */ - __u32 sisfb_scalelcd; - __u32 sisfb_specialtiming; + __u32 sisfb_curfstn; /* currently running FSTN/DSTN mode */ + __u32 sisfb_curdstn; - __u8 sisfb_haveemi; - __u8 sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33; - __u8 sisfb_haveemilcd; + __u16 sisfb_pci_vendor; /* PCI vendor (SiS or XGI) */ - __u8 sisfb_lcdpdca; /* PanelDelayCompensation for LCD-via-CRT1 */ + __u32 sisfb_vbflags2; /* ivideo->vbflags2 */ - __u16 sisfb_tvxpos, sisfb_tvypos; /* Warning: Values + 32 ! */ + __u8 sisfb_can_post; /* sisfb can POST this card */ + __u8 sisfb_card_posted; /* card is POSTED */ + __u8 sisfb_was_boot_device; /* This card was the boot video device (ie is primary) */ - __u8 reserved[208]; /* for future use */ + __u8 reserved[183]; /* for future use */ +}; + +#define SISFB_CMD_GETVBFLAGS 0x55AA0001 /* no arg; result[1] = vbflags */ +#define SISFB_CMD_SWITCHCRT1 0x55AA0010 /* arg[0]: 99 = query, 0 = off, 1 = on */ +/* more to come */ + +#define SISFB_CMD_ERR_OK 0x80000000 /* command succeeded */ +#define SISFB_CMD_ERR_LOCKED 0x80000001 /* sisfb is locked */ +#define SISFB_CMD_ERR_EARLY 0x80000002 /* request before sisfb took over gfx system */ +#define SISFB_CMD_ERR_NOVB 0x80000003 /* No video bridge */ +#define SISFB_CMD_ERR_NOCRT2 0x80000004 /* can't change CRT1 status, CRT2 disabled */ +/* more to come */ +#define SISFB_CMD_ERR_UNKNOWN 0x8000ffff /* Unknown command */ +#define SISFB_CMD_ERR_OTHER 0x80010000 /* Other error */ + +/* Argument for SISFB_CMD ioctl */ +struct sisfb_cmd { + __u32 sisfb_cmd; + __u32 sisfb_arg[16]; + __u32 sisfb_result[4]; }; /* Addtional IOCTLs for communication sisfb <> X driver */ /* If changing this, vgatypes.h must also be changed (for X driver) */ /* ioctl for identifying and giving some info (esp. memory heap start) */ -#define SISFB_GET_INFO_SIZE _IOR(0xF3,0x00,__u32) -#define SISFB_GET_INFO _IOR(0xF3,0x01,struct _SISFB_INFO) +#define SISFB_GET_INFO_SIZE _IOR(0xF3,0x00,__u32) +#define SISFB_GET_INFO _IOR(0xF3,0x01,struct sisfb_info) /* ioctrl to get current vertical retrace status */ -#define SISFB_GET_VBRSTATUS _IOR(0xF3,0x02,__u32) +#define SISFB_GET_VBRSTATUS _IOR(0xF3,0x02,__u32) /* ioctl to enable/disable panning auto-maximize (like nomax parameter) */ -#define SISFB_GET_AUTOMAXIMIZE _IOR(0xF3,0x03,__u32) -#define SISFB_SET_AUTOMAXIMIZE _IOW(0xF3,0x03,__u32) +#define SISFB_GET_AUTOMAXIMIZE _IOR(0xF3,0x03,__u32) +#define SISFB_SET_AUTOMAXIMIZE _IOW(0xF3,0x03,__u32) /* ioctls to relocate TV output (x=D[31:16], y=D[15:0], + 32)*/ -#define SISFB_GET_TVPOSOFFSET _IOR(0xF3,0x04,__u32) -#define SISFB_SET_TVPOSOFFSET _IOW(0xF3,0x04,__u32) +#define SISFB_GET_TVPOSOFFSET _IOR(0xF3,0x04,__u32) +#define SISFB_SET_TVPOSOFFSET _IOW(0xF3,0x04,__u32) + +/* ioctl for internal sisfb commands (sisfbctrl) */ +#define SISFB_COMMAND _IOWR(0xF3,0x05,struct sisfb_cmd) /* ioctl for locking sisfb (no register access during lock) */ /* As of now, only used to avoid register access during * the ioctls listed above. */ -#define SISFB_SET_LOCK _IOW(0xF3,0x06,__u32) - -/* more to come soon */ +#define SISFB_SET_LOCK _IOW(0xF3,0x06,__u32) /* ioctls 0xF3 up to 0x3F reserved for sisfb */ @@ -165,7 +184,7 @@ struct _SISFB_INFO { /* The following are deprecated and should not be used anymore: */ /****************************************************************/ /* ioctl for identifying and giving some info (esp. memory heap start) */ -#define SISFB_GET_INFO_OLD _IOR('n',0xF8,__u32) +#define SISFB_GET_INFO_OLD _IOR('n',0xF8,__u32) /* ioctrl to get current vertical retrace status */ #define SISFB_GET_VBRSTATUS_OLD _IOR('n',0xF9,__u32) /* ioctl to enable/disable panning auto-maximize (like nomax parameter) */ @@ -177,8 +196,8 @@ struct _SISFB_INFO { /* For fb memory manager (FBIO_ALLOC, FBIO_FREE) */ struct sis_memreq { - __u32 offset; - __u32 size; + __u32 offset; + __u32 size; }; /**********************************************/ @@ -187,12 +206,19 @@ struct sis_memreq { /**********************************************/ #ifdef __KERNEL__ + +#include <linux/pci.h> + #define UNKNOWN_VGA 0 #define SIS_300_VGA 1 #define SIS_315_VGA 2 +#define SISFB_HAVE_MALLOC_NEW extern void sis_malloc(struct sis_memreq *req); +extern void sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req); + extern void sis_free(u32 base); +extern void sis_free_new(struct pci_dev *pdev, u32 base); #endif #endif -- GitLab From 6062bfa1644f401c08e78d5c8a161f7d11c5c830 Mon Sep 17 00:00:00 2001 From: Olaf Hering <olh@suse.de> Date: Fri, 9 Sep 2005 13:04:55 -0700 Subject: [PATCH 234/563] [PATCH] better error handing in savagefb_probe err remains uninitialized of pci_request_regions fails. Found by Thorsten Kukuk, I added a few more checks. Signed-off-by: Olaf Hering <olh@suse.de> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/savage/savagefb_driver.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index abad90a3702c2..86522888e0aa5 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -1976,12 +1976,11 @@ static int __devinit savage_init_fb_info (struct fb_info *info, info->pixmap.buf_align = 4; info->pixmap.access_align = 32; - fb_alloc_cmap (&info->cmap, NR_PALETTE, 0); + err = fb_alloc_cmap (&info->cmap, NR_PALETTE, 0); + if (!err) info->flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT; - - err = 0; } #endif return err; @@ -2009,14 +2008,14 @@ static int __devinit savagefb_probe (struct pci_dev* dev, if (err) goto failed_enable; - if (pci_request_regions(dev, "savagefb")) { + if ((err = pci_request_regions(dev, "savagefb"))) { printk(KERN_ERR "cannot request PCI regions\n"); goto failed_enable; } err = -ENOMEM; - if (savage_init_fb_info(info, dev, id)) + if ((err = savage_init_fb_info(info, dev, id))) goto failed_init; err = savage_map_mmio(info); @@ -2024,6 +2023,7 @@ static int __devinit savagefb_probe (struct pci_dev* dev, goto failed_mmio; video_len = savage_init_hw(par); + /* FIXME: cant be negative */ if (video_len < 0) { err = video_len; goto failed_mmio; -- GitLab From 9fa68eae9f8291a98bfe00b94b78f72eb253165a Mon Sep 17 00:00:00 2001 From: Knut Petersen <Knut_Petersen@t-online.de> Date: Fri, 9 Sep 2005 13:04:56 -0700 Subject: [PATCH 235/563] [PATCH] framebuffer: new driver for cyberblade/i1 graphics core This is a framebuffer driver for the Cyberblade/i1 graphics core. Currently tridenfb claims to support the cyberblade/i1 graphics core. This is of very limited truth. Even vesafb is faster and provides more working modes and a much better quality of the video signal. There is a great number of bugs in tridentfb ... but most often it is impossible to decide if these bugs are real bugs or if fixing them for the cyberblade/i1 core would break support for one of the other supported chips. Tridentfb seems to be unmaintained,and documentation for most of the supported chips is not available. So "fixing" cyberblade/i1 support inside of tridentfb was not an option, it would have caused numerous if(CYBERBLADEi1) else ... cases and would have rendered the code to be almost unmaintainable. A first version of this driver was published on 2005-07-31. A fix for a bug reported by Jochen Hein was integrated as well as some changes requested by Antonino A. Daplas. A message has been added to tridentfb to inform current users of tridentfb to switch to cyblafb if the cyberblade/i1 graphics core is detected. This patch is one logical change, but because of the included documentation it is bigger than 70kb. Therefore it is not sent to lkml and linux-fbdev-devel, Signed-off-by: Knut Petersen <Knut_Petersen@t-online.de> Cc: Muli Ben-Yehuda <mulix@mulix.org> Acked-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/fb/cyblafb/bugs | 14 + Documentation/fb/cyblafb/credits | 7 + Documentation/fb/cyblafb/documentation | 17 + Documentation/fb/cyblafb/fb.modes | 155 +++ Documentation/fb/cyblafb/performance | 80 ++ Documentation/fb/cyblafb/todo | 32 + Documentation/fb/cyblafb/usage | 206 ++++ Documentation/fb/cyblafb/whycyblafb | 85 ++ MAINTAINERS | 6 + drivers/video/Kconfig | 31 +- drivers/video/Makefile | 3 +- drivers/video/cyblafb.c | 1456 ++++++++++++++++++++++++ drivers/video/tridentfb.c | 5 + include/video/cyblafb.h | 171 +++ 14 files changed, 2266 insertions(+), 2 deletions(-) create mode 100644 Documentation/fb/cyblafb/bugs create mode 100644 Documentation/fb/cyblafb/credits create mode 100644 Documentation/fb/cyblafb/documentation create mode 100644 Documentation/fb/cyblafb/fb.modes create mode 100644 Documentation/fb/cyblafb/performance create mode 100644 Documentation/fb/cyblafb/todo create mode 100644 Documentation/fb/cyblafb/usage create mode 100644 Documentation/fb/cyblafb/whycyblafb create mode 100644 drivers/video/cyblafb.c create mode 100644 include/video/cyblafb.h diff --git a/Documentation/fb/cyblafb/bugs b/Documentation/fb/cyblafb/bugs new file mode 100644 index 0000000000000..f90cc66ea9197 --- /dev/null +++ b/Documentation/fb/cyblafb/bugs @@ -0,0 +1,14 @@ +Bugs +==== + +I currently don't know of any bug. Please do send reports to: + - linux-fbdev-devel@lists.sourceforge.net + - Knut_Petersen@t-online.de. + + +Untested features +================= + +All LCD stuff is untested. If it worked in tridentfb, it should work in +cyblafb. Please test and report the results to Knut_Petersen@t-online.de. + diff --git a/Documentation/fb/cyblafb/credits b/Documentation/fb/cyblafb/credits new file mode 100644 index 0000000000000..0eb3b443dc2b1 --- /dev/null +++ b/Documentation/fb/cyblafb/credits @@ -0,0 +1,7 @@ +Thanks to +========= + * Alan Hourihane, for writing the X trident driver + * Jani Monoses, for writing the tridentfb driver + * Antonino A. Daplas, for review of the first published + version of cyblafb and some code + * Jochen Hein, for testing and a helpfull bug report diff --git a/Documentation/fb/cyblafb/documentation b/Documentation/fb/cyblafb/documentation new file mode 100644 index 0000000000000..bb1aac0484254 --- /dev/null +++ b/Documentation/fb/cyblafb/documentation @@ -0,0 +1,17 @@ +Available Documentation +======================= + +Apollo PLE 133 Chipset VT8601A North Bridge Datasheet, Rev. 1.82, October 22, +2001, available from VIA: + + http://www.viavpsd.com/product/6/15/DS8601A182.pdf + +The datasheet is incomplete, some registers that need to be programmed are not +explained at all and important bits are listed as "reserved". But you really +need the datasheet to understand the code. "p. xxx" comments refer to page +numbers of this document. + +XFree/XOrg drivers are available and of good quality, looking at the code +there is a good idea if the datasheet does not provide enough information +or if the datasheet seems to be wrong. + diff --git a/Documentation/fb/cyblafb/fb.modes b/Documentation/fb/cyblafb/fb.modes new file mode 100644 index 0000000000000..cf4351fc32ff6 --- /dev/null +++ b/Documentation/fb/cyblafb/fb.modes @@ -0,0 +1,155 @@ +# +# Sample fb.modes file +# +# Provides an incomplete list of working modes for +# the cyberblade/i1 graphics core. +# +# The value 4294967256 is used instead of -40. Of course, -40 is not +# a really reasonable value, but chip design does not always follow +# logic. Believe me, it's ok, and it's the way the BIOS does it. +# +# fbset requires 4294967256 in fb.modes and -40 as an argument to +# the -t parameter. That's also not too reasonable, and it might change +# in the future or might even be differt for your current version. +# + +mode "640x480-50" + geometry 640 480 640 3756 8 + timings 47619 4294967256 24 17 0 216 3 +endmode + +mode "640x480-60" + geometry 640 480 640 3756 8 + timings 39682 4294967256 24 17 0 216 3 +endmode + +mode "640x480-70" + geometry 640 480 640 3756 8 + timings 34013 4294967256 24 17 0 216 3 +endmode + +mode "640x480-72" + geometry 640 480 640 3756 8 + timings 33068 4294967256 24 17 0 216 3 +endmode + +mode "640x480-75" + geometry 640 480 640 3756 8 + timings 31746 4294967256 24 17 0 216 3 +endmode + +mode "640x480-80" + geometry 640 480 640 3756 8 + timings 29761 4294967256 24 17 0 216 3 +endmode + +mode "640x480-85" + geometry 640 480 640 3756 8 + timings 28011 4294967256 24 17 0 216 3 +endmode + +mode "800x600-50" + geometry 800 600 800 3221 8 + timings 30303 96 24 14 0 136 11 +endmode + +mode "800x600-60" + geometry 800 600 800 3221 8 + timings 25252 96 24 14 0 136 11 +endmode + +mode "800x600-70" + geometry 800 600 800 3221 8 + timings 21645 96 24 14 0 136 11 +endmode + +mode "800x600-72" + geometry 800 600 800 3221 8 + timings 21043 96 24 14 0 136 11 +endmode + +mode "800x600-75" + geometry 800 600 800 3221 8 + timings 20202 96 24 14 0 136 11 +endmode + +mode "800x600-80" + geometry 800 600 800 3221 8 + timings 18939 96 24 14 0 136 11 +endmode + +mode "800x600-85" + geometry 800 600 800 3221 8 + timings 17825 96 24 14 0 136 11 +endmode + +mode "1024x768-50" + geometry 1024 768 1024 2815 8 + timings 19054 144 24 29 0 120 3 +endmode + +mode "1024x768-60" + geometry 1024 768 1024 2815 8 + timings 15880 144 24 29 0 120 3 +endmode + +mode "1024x768-70" + geometry 1024 768 1024 2815 8 + timings 13610 144 24 29 0 120 3 +endmode + +mode "1024x768-72" + geometry 1024 768 1024 2815 8 + timings 13232 144 24 29 0 120 3 +endmode + +mode "1024x768-75" + geometry 1024 768 1024 2815 8 + timings 12703 144 24 29 0 120 3 +endmode + +mode "1024x768-80" + geometry 1024 768 1024 2815 8 + timings 11910 144 24 29 0 120 3 +endmode + +mode "1024x768-85" + geometry 1024 768 1024 2815 8 + timings 11209 144 24 29 0 120 3 +endmode + +mode "1280x1024-50" + geometry 1280 1024 1280 2662 8 + timings 11114 232 16 39 0 160 3 +endmode + +mode "1280x1024-60" + geometry 1280 1024 1280 2662 8 + timings 9262 232 16 39 0 160 3 +endmode + +mode "1280x1024-70" + geometry 1280 1024 1280 2662 8 + timings 7939 232 16 39 0 160 3 +endmode + +mode "1280x1024-72" + geometry 1280 1024 1280 2662 8 + timings 7719 232 16 39 0 160 3 +endmode + +mode "1280x1024-75" + geometry 1280 1024 1280 2662 8 + timings 7410 232 16 39 0 160 3 +endmode + +mode "1280x1024-80" + geometry 1280 1024 1280 2662 8 + timings 6946 232 16 39 0 160 3 +endmode + +mode "1280x1024-85" + geometry 1280 1024 1280 2662 8 + timings 6538 232 16 39 0 160 3 +endmode + diff --git a/Documentation/fb/cyblafb/performance b/Documentation/fb/cyblafb/performance new file mode 100644 index 0000000000000..eb4e47a9cea62 --- /dev/null +++ b/Documentation/fb/cyblafb/performance @@ -0,0 +1,80 @@ +Speed +===== + +CyBlaFB is much faster than tridentfb and vesafb. Compare the performance data +for mode 1280x1024-[8,16,32]@61 Hz. + +Test 1: Cat a file with 2000 lines of 0 characters. +Test 2: Cat a file with 2000 lines of 80 characters. +Test 3: Cat a file with 2000 lines of 160 characters. + +All values show system time use in seconds, kernel 2.6.12 was used for +the measurements. 2.6.13 is a bit slower, 2.6.14 hopefully will include a +patch that speeds up kernel bitblitting a lot ( > 20%). + ++-----------+-----------------------------------------------------+ +| | not accelerated | +| TRIDENTFB +-----------------+-----------------+-----------------+ +| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp | +| | noypan | ypan | noypan | ypan | noypan | ypan | ++-----------+--------+--------+--------+--------+--------+--------+ +| Test 1 | 4.31 | 4.33 | 6.05 | 12.81 | ---- | ---- | +| Test 2 | 67.94 | 5.44 | 123.16 | 14.79 | ---- | ---- | +| Test 3 | 131.36 | 6.55 | 240.12 | 16.76 | ---- | ---- | ++-----------+--------+--------+--------+--------+--------+--------+ +| Comments | | | completely bro- | +| | | | ken, monitor | +| | | | switches off | ++-----------+-----------------+-----------------+-----------------+ + + ++-----------+-----------------------------------------------------+ +| | accelerated | +| TRIDENTFB +-----------------+-----------------+-----------------+ +| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp | +| | noypan | ypan | noypan | ypan | noypan | ypan | ++-----------+--------+--------+--------+--------+--------+--------+ +| Test 1 | ---- | ---- | 20.62 | 1.22 | ---- | ---- | +| Test 2 | ---- | ---- | 22.61 | 3.19 | ---- | ---- | +| Test 3 | ---- | ---- | 24.59 | 5.16 | ---- | ---- | ++-----------+--------+--------+--------+--------+--------+--------+ +| Comments | broken, writing | broken, ok only | completely bro- | +| | to wrong places | if bgcolor is | ken, monitor | +| | on screen + bug | black, bug in | switches off | +| | in fillrect() | fillrect() | | ++-----------+-----------------+-----------------+-----------------+ + + ++-----------+-----------------------------------------------------+ +| | not accelerated | +| VESAFB +-----------------+-----------------+-----------------+ +| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp | +| | noypan | ypan | noypan | ypan | noypan | ypan | ++-----------+--------+--------+--------+--------+--------+--------+ +| Test 1 | 4.26 | 3.76 | 5.99 | 7.23 | ---- | ---- | +| Test 2 | 65.65 | 4.89 | 120.88 | 9.08 | ---- | ---- | +| Test 3 | 126.91 | 5.94 | 235.77 | 11.03 | ---- | ---- | ++-----------+--------+--------+--------+--------+--------+--------+ +| Comments | vga=0x307 | vga=0x31a | vga=0x31b not | +| | fh=80kHz | fh=80kHz | supported by | +| | fv=75kHz | fv=75kHz | video BIOS and | +| | | | hardware | ++-----------+-----------------+-----------------+-----------------+ + + ++-----------+-----------------------------------------------------+ +| | accelerated | +| CYBLAFB +-----------------+-----------------+-----------------+ +| | 8 bpp | 16 bpp | 32 bpp | +| | noypan | ypan | noypan | ypan | noypan | ypan | ++-----------+--------+--------+--------+--------+--------+--------+ +| Test 1 | 8.02 | 0.23 | 19.04 | 0.61 | 57.12 | 2.74 | +| Test 2 | 8.38 | 0.55 | 19.39 | 0.92 | 57.54 | 3.13 | +| Test 3 | 8.73 | 0.86 | 19.74 | 1.24 | 57.95 | 3.51 | ++-----------+--------+--------+--------+--------+--------+--------+ +| Comments | | | | +| | | | | +| | | | | +| | | | | ++-----------+-----------------+-----------------+-----------------+ + diff --git a/Documentation/fb/cyblafb/todo b/Documentation/fb/cyblafb/todo new file mode 100644 index 0000000000000..80fb2f89b6c17 --- /dev/null +++ b/Documentation/fb/cyblafb/todo @@ -0,0 +1,32 @@ +TODO / Missing features +======================= + +Verify LCD stuff "stretch" and "center" options are + completely untested ... this code needs to be + verified. As I don't have access to such + hardware, please contact me if you are + willing run some tests. + +Interlaced video modes The reason that interleaved + modes are disabled is that I do not know + the meaning of the vertical interlace + parameter. Also the datasheet mentions a + bit d8 of a horizontal interlace parameter, + but nowhere the lower 8 bits. Please help + if you can. + +low-res double scan modes Who needs it? + +accelerated color blitting Who needs it? The console driver does use color + blitting for nothing but drawing the penguine, + everything else is done using color expanding + blitting of 1bpp character bitmaps. + +xpanning Who needs it? + +ioctls Who needs it? + +TV-out Will be done later + +??? Feel free to contact me if you have any + feature requests diff --git a/Documentation/fb/cyblafb/usage b/Documentation/fb/cyblafb/usage new file mode 100644 index 0000000000000..e627c8f542115 --- /dev/null +++ b/Documentation/fb/cyblafb/usage @@ -0,0 +1,206 @@ +CyBlaFB is a framebuffer driver for the Cyberblade/i1 graphics core integrated +into the VIA Apollo PLE133 (aka vt8601) south bridge. It is developed and +tested using a VIA EPIA 5000 board. + +Cyblafb - compiled into the kernel or as a module? +================================================== + +You might compile cyblafb either as a module or compile it permanently into the +kernel. + +Unless you have a real reason to do so you should not compile both vesafb and +cyblafb permanently into the kernel. It's possible and it helps during the +developement cycle, but it's useless and will at least block some otherwise +usefull memory for ordinary users. + +Selecting Modes +=============== + + Startup Mode + ============ + + First of all, you might use the "vga=???" boot parameter as it is + documented in vesafb.txt and svga.txt. Cyblafb will detect the video + mode selected and will use the geometry and timings found by + inspecting the hardware registers. + + video=cyblafb vga=0x317 + + Alternatively you might use a combination of the mode, ref and bpp + parameters. If you compiled the driver into the kernel, add something + like this to the kernel command line: + + video=cyblafb:1280x1024,bpp=16,ref=50 ... + + If you compiled the driver as a module, the same mode would be + selected by the following command: + + modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ... + + None of the modes possible to select as startup modes are affected by + the problems described at the end of the next subsection. + + Mode changes using fbset + ======================== + + You might use fbset to change the video mode, see "man fbset". Cyblafb + generally does assume that you know what you are doing. But it does + some checks, especially those that are needed to prevent you from + damaging your hardware. + + - only 8, 16, 24 and 32 bpp video modes are accepted + - interlaced video modes are not accepted + - double scan video modes are not accepted + - if a flat panel is found, cyblafb does not allow you + to program a resolution higher than the physical + resolution of the flat panel monitor + - cyblafb does not allow xres to differ from xres_virtual + - cyblafb does not allow vclk to exceed 230 MHz. As 32 bpp + and (currently) 24 bit modes use a doubled vclk internally, + the dotclock limit as seen by fbset is 115 MHz for those + modes and 230 MHz for 8 and 16 bpp modes. + + Any request that violates the rules given above will be ignored and + fbset will return an error. + + If you program a virtual y resolution higher than the hardware limit, + cyblafb will silently decrease that value to the highest possible + value. + + Attempts to disable acceleration are ignored. + + Some video modes that should work do not work as expected. If you use + the standard fb.modes, fbset 640x480-60 will program that mode, but + you will see a vertical area, about two characters wide, with only + much darker characters than the other characters on the screen. + Cyblafb does allow that mode to be set, as it does not violate the + official specifications. It would need a lot of code to reliably sort + out all invalid modes, playing around with the margin values will + give a valid mode quickly. And if cyblafb would detect such an invalid + mode, should it silently alter the requested values or should it + report an error? Both options have some pros and cons. As stated + above, none of the startup modes are affected, and if you set + verbosity to 1 or higher, cyblafb will print the fbset command that + would be needed to program that mode using fbset. + + +Other Parameters +================ + + +crt don't autodetect, assume monitor connected to + standard VGA connector + +fp don't autodetect, assume flat panel display + connected to flat panel monitor interface + +nativex inform driver about native x resolution of + flat panel monitor connected to special + interface (should be autodetected) + +stretch stretch image to adapt low resolution modes to + higer resolutions of flat panel monitors + connected to special interface + +center center image to adapt low resolution modes to + higer resolutions of flat panel monitors + connected to special interface + +memsize use if autodetected memsize is wrong ... + should never be necessary + +nopcirr disable PCI read retry +nopciwr disable PCI write retry +nopcirb disable PCI read bursts +nopciwb disable PCI write bursts + +bpp bpp for specified modes + valid values: 8 || 16 || 24 || 32 + +ref refresh rate for specified mode + valid values: 50 <= ref <= 85 + +mode 640x480 or 800x600 or 1024x768 or 1280x1024 + if not specified, the startup mode will be detected + and used, so you might also use the vga=??? parameter + described in vesafb.txt. If you do not specify a mode, + bpp and ref parameters are ignored. + +verbosity 0 is the default, increase to at least 2 for every + bug report! + +vesafb allows cyblafb to be loaded after vesafb has been + loaded. See sections "Module unloading ...". + + +Development hints +================= + +It's much faster do compile a module and to load the new version after +unloading the old module than to compile a new kernel and to reboot. So if you +try to work on cyblafb, it might be a good idea to use cyblafb as a module. +In real life, fast often means dangerous, and that's also the case here. If +you introduce a serious bug when cyblafb is compiled into the kernel, the +kernel will lock or oops with a high probability before the file system is +mounted, and the danger for your data is low. If you load a broken own version +of cyblafb on a running system, the danger for the integrity of the file +system is much higher as you might need a hard reset afterwards. Decide +yourself. + +Module unloading, the vfb method +================================ + +If you want to unload/reload cyblafb using the virtual framebuffer, you need +to enable vfb support in the kernel first. After that, load the modules as +shown below: + + modprobe vfb vfb_enable=1 + modprobe fbcon + modprobe cyblafb + fbset -fb /dev/fb1 1280x1024-60 -vyres 2662 + con2fb /dev/fb1 /dev/tty1 + ... + +If you now made some changes to cyblafb and want to reload it, you might do it +as show below: + + con2fb /dev/fb0 /dev/tty1 + ... + rmmod cyblafb + modprobe cyblafb + con2fb /dev/fb1 /dev/tty1 + ... + +Of course, you might choose another mode, and most certainly you also want to +map some other /dev/tty* to the real framebuffer device. You might also choose +to compile fbcon as a kernel module or place it permanently in the kernel. + +I do not know of any way to unload fbcon, and fbcon will prevent the +framebuffer device loaded first from unloading. [If there is a way, then +please add a description here!] + +Module unloading, the vesafb method +=================================== + +Configure the kernel: + + <*> Support for frame buffer devices + [*] VESA VGA graphics support + <M> Cyberblade/i1 support + +Add e.g. "video=vesafb:ypan vga=0x307" to the kernel parameters. The ypan +parameter is important, choose any vga parameter you like as long as it is +a graphics mode. + +After booting, load cyblafb without any mode and bpp parameter and assign +cyblafb to individual ttys using con2fb, e.g.: + + modprobe cyblafb vesafb=1 + con2fb /dev/fb1 /dev/tty1 + +Unloading cyblafb works without problems after you assign vesafb to all +ttys again, e.g.: + + con2fb /dev/fb0 /dev/tty1 + rmmod cyblafb + diff --git a/Documentation/fb/cyblafb/whycyblafb b/Documentation/fb/cyblafb/whycyblafb new file mode 100644 index 0000000000000..a123bc11e698b --- /dev/null +++ b/Documentation/fb/cyblafb/whycyblafb @@ -0,0 +1,85 @@ +I tried the following framebuffer drivers: + + - TRIDENTFB is full of bugs. Acceleration is broken for Blade3D + graphics cores like the cyberblade/i1. It claims to support a great + number of devices, but documentation for most of these devices is + unfortunately not available. There is _no_ reason to use tridentfb + for cyberblade/i1 + CRT users. VESAFB is faster, and the one + advantage, mode switching, is broken in tridentfb. + + - VESAFB is used by many distributions as a standard. Vesafb does + not support mode switching. VESAFB is a bit faster than the working + configurations of TRIDENTFB, but it is still too slow, even if you + use ypan. + + - EPIAFB (you'll find it on sourceforge) supports the Cyberblade/i1 + graphics core, but it still has serious bugs and developement seems + to have stopped. This is the one driver with TV-out support. If you + do need this feature, try epiafb. + +None of these drivers was a real option for me. + +I believe that is unreasonable to change code that announces to support 20 +devices if I only have more or less sufficient documentation for exactly one +of these. The risk of breaking device foo while fixing device bar is too high. + +So I decided to start CyBlaFB as a stripped down tridentfb. + +All code specific to other Trident chips has been removed. After that there +were a lot of cosmetic changes to increase the readability of the code. All +register names were changed to those mnemonics used in the datasheet. Function +and macro names were changed if they hindered easy understanding of the code. + +After that I debugged the code and implemented some new features. I'll try to +give a little summary of the main changes: + + - calculation of vertical and horizontal timings was fixed + + - video signal quality has been improved dramatically + + - acceleration: + + - fillrect and copyarea were fixed and reenabled + + - color expanding imageblit was newly implemented, color + imageblit (only used to draw the penguine) still uses the + generic code. + + - init of the acceleration engine was improved and moved to a + place where it really works ... + + - sync function has a timeout now and tries to reset and + reinit the accel engine if necessary + + - fewer slow copyarea calls when doing ypan scrolling by using + undocumented bit d21 of screen start address stored in + CR2B[5]. BIOS does use it also, so this should be safe. + + - cyblafb rejects any attempt to set modes that would cause vclk + values above reasonable 230 MHz. 32bit modes use a clock + multiplicator of 2, so fbset does show the correct values for + pixclock but not for vclk in this case. The fbset limit is 115 MHz + for 32 bpp modes. + + - cyblafb rejects modes known to be broken or unimplemented (all + interlaced modes, all doublescan modes for now) + + - cyblafb now works independant of the video mode in effect at startup + time (tridentfb does not init all needed registers to reasonable + values) + + - switching between video modes does work reliably now + + - the first video mode now is the one selected on startup using the + vga=???? mechanism or any of + - 640x480, 800x600, 1024x768, 1280x1024 + - 8, 16, 24 or 32 bpp + - refresh between 50 Hz and 85 Hz, 1 Hz steps (1280x1024-32 + is limited to 63Hz) + + - pci retry and pci burst mode are settable (try to disable if you + experience latency problems) + + - built as a module cyblafb might be unloaded and reloaded using + the vfb module and con2vt or might be used together with vesafb + diff --git a/MAINTAINERS b/MAINTAINERS index 8429bdb1d2a1a..9c9a86d0685a5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -626,6 +626,12 @@ M: rmk@arm.linux.org.uk W: http://www.arm.linux.org.uk/ S: Maintained +CYBLAFB FRAMEBUFFER DRIVER +P: Knut Petersen +M: Knut_Petersen@t-online.de +L: linux-fbdev-devel@lists.sourceforge.net +S: Maintained + CYCLADES 2X SYNC CARD DRIVER P: Arnaldo Carvalho de Melo M: acme@conectiva.com.br diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e906b54217951..e27aefd49ea3a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1177,6 +1177,32 @@ config FB_VOODOO1 Please read the <file:Documentation/fb/README-sstfb.txt> for supported options and other important info support. +config FB_CYBLA + tristate "Cyberblade/i1 support" + depends on FB && PCI + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select VIDEO_SELECT + ---help--- + This driver is supposed to support the Trident Cyberblade/i1 + graphics core integrated in the VIA VT8601A North Bridge, + also known as VIA Apollo PLE133. + + Status: + - Developed, tested and working on EPIA 5000 and EPIA 800. + - Does work reliable on all systems with CRT/LCD connected to + normal VGA ports. + - Should work on systems that do use the internal LCD port, but + this is absolutely not tested. + + Character imageblit, copyarea and rectangle fill are hw accelerated, + ypan scrolling is used by default. + + Please do read <file:Documentation/fb/cyblafb/*>. + + To compile this driver as a module, choose M here: the + module will be called cyblafb. + config FB_TRIDENT tristate "Trident support" depends on FB && PCI @@ -1190,8 +1216,12 @@ config FB_TRIDENT but also on some motherboards. For more information, read <file:Documentation/fb/tridentfb.txt> + Cyberblade/i1 support will be removed soon, use the cyblafb driver + instead. + Say Y if you have such a graphics board. + To compile this driver as a module, choose M here: the module will be called tridentfb. @@ -1202,7 +1232,6 @@ config FB_TRIDENT_ACCEL This will compile the Trident frame buffer device with acceleration functions. - config FB_PM3 tristate "Permedia3 support" depends on FB && PCI && BROKEN diff --git a/drivers/video/Makefile b/drivers/video/Makefile index b018df4e95c84..8478d217aaf07 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -50,7 +50,8 @@ obj-$(CONFIG_FB_CT65550) += chipsfb.o obj-$(CONFIG_FB_IMSTT) += imsttfb.o obj-$(CONFIG_FB_S3TRIO) += S3triofb.o obj-$(CONFIG_FB_FM2) += fm2fb.o -obj-$(CONFIG_FB_TRIDENT) += tridentfb.o +obj-$(CONFIG_FB_CYBLA) += cyblafb.o +obj-$(CONFIG_FB_TRIDENT) += tridentfb.o obj-$(CONFIG_FB_STI) += stifb.o obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c new file mode 100644 index 0000000000000..ae2762cb56082 --- /dev/null +++ b/drivers/video/cyblafb.c @@ -0,0 +1,1456 @@ +/* + * Frame buffer driver for Trident Cyberblade/i1 graphics core + * + * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de> + * + * CREDITS: + * tridentfb.c by Jani Monoses + * see files above for further credits + * + * TODO: + * + */ + +#define CYBLAFB_DEBUG 0 + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/types.h> +#include <video/cyblafb.h> + +#define VERSION "0.54" + +struct cyblafb_par { + u32 pseudo_pal[16]; + struct fb_ops ops; +}; + +static struct fb_fix_screeninfo cyblafb_fix __devinitdata = { + .id = "CyBla", + .type = FB_TYPE_PACKED_PIXELS, + .ypanstep = 1, + .visual = FB_VISUAL_PSEUDOCOLOR, + .accel = FB_ACCEL_NONE, +}; + +static char *mode __devinitdata = NULL; +static int bpp __devinitdata = 8; +static int ref __devinitdata = 75; +static int fp __devinitdata; +static int crt __devinitdata; +static int memsize __devinitdata; +static int vesafb __devinitdata; + +static int nativex; +static int center; +static int stretch; +static int pciwb = 1; +static int pcirb = 1; +static int pciwr = 1; +static int pcirr = 1; +static int verbosity; +static int displaytype; + +static void __iomem * io_virt; // iospace virtual memory address + +module_param(mode,charp,0); +module_param(bpp,int,0); +module_param(ref,int,0); +module_param(fp,int,0); +module_param(crt,int,0); +module_param(nativex,int,0); +module_param(center,int,0); +module_param(stretch,int,0); +module_param(pciwb,int,0); +module_param(pcirb,int,0); +module_param(pciwr,int,0); +module_param(pcirr,int,0); +module_param(memsize,int,0); +module_param(verbosity,int,0); +module_param(vesafb,int,0); + +//========================================= +// +// Port access macros for memory mapped io +// +//========================================= + +#define out8(r,v) writeb(v,io_virt+r) +#define out32(r,v) writel(v,io_virt+r) +#define in8(r) readb(io_virt+r) +#define in32(r) readl(io_virt+r) + +//====================================== +// +// Hardware access inline functions +// +//====================================== + +static inline unsigned char read3X4(int reg) +{ + out8(0x3D4,reg); + return in8(0x3D5); +} + +static inline unsigned char read3C4(int reg) +{ + out8(0x3C4,reg); + return in8(0x3C5); +} + +static inline unsigned char read3CE(int reg) +{ + out8(0x3CE,reg); + return in8(0x3CF); +} + +static inline void write3X4(int reg,unsigned char val) +{ + out8(0x3D4,reg); + out8(0x3D5,val); +} + +static inline void write3C4(int reg,unsigned char val) +{ + out8(0x3C4,reg); + out8(0x3C5,val); +} + +static inline void write3CE(int reg,unsigned char val) +{ + out8(0x3CE,reg); + out8(0x3CF,val); +} + +static inline void write3C0(int reg,unsigned char val) +{ + in8(0x3DA); // read to reset index + out8(0x3C0,reg); + out8(0x3C0,val); +} + +//================================================= +// +// Enable memory mapped io and unprotect registers +// +//================================================= + +static inline void enable_mmio(void) +{ + int tmp; + + outb(0x0B,0x3C4); + inb(0x3C5); // Set NEW mode + outb(SR0E,0x3C4); // write enable a lot of extended ports + outb(0x80,0x3C5); + + outb(SR11,0x3C4); // write enable those extended ports that + outb(0x87,0x3C5); // are not affected by SR0E_New + + outb(CR1E,0x3d4); // clear write protect bit for port 0x3c2 + tmp=inb(0x3d5) & 0xBF; + outb(CR1E,0x3d4); + outb(tmp,0x3d5); + + outb(CR39,0x3D4); + outb(inb(0x3D5)|0x01,0x3D5); // Enable mmio, everything else untouched +} + +//================================================= +// +// Set pixel clock VCLK1 +// - multipliers set elswhere +// - freq in units of 0.01 MHz +// +//================================================= + +static void set_vclk(struct cyblafb_par *par, int freq) +{ + u32 m,n,k; + int f,fi,d,di; + u8 lo=0,hi=0; + + d = 2000; + k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3; + for(m = 0;m<64;m++) + for(n = 0;n<250;n++) { // max 249 is a hardware limit for cybla/i1 ! + fi = (int)(((5864727*(n+8))/((m+2)*(1<<k)))>>12); + if ((di = abs(fi - freq)) < d) { + d = di; + f = fi; + lo = (u8) n; + hi = (u8) ((k<<6) | m); + } + } + write3C4(SR19,hi); + write3C4(SR18,lo); + if(verbosity > 1) + output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n", + freq/100,freq%100,(hi&0xc0)>>6,hi&0x3f,lo); +} + +//================================================ +// +// Cyberblade specific Graphics Engine (GE) setup +// +//================================================ + +static void cyblafb_setup_GE(int pitch,int bpp) +{ + int base = (pitch>>3)<<20; + + switch (bpp) { + case 8: base |= (0<<29); break; + case 15: base |= (5<<29); break; + case 16: base |= (1<<29); break; + case 24: + case 32: base |= (2<<29); break; + } + + write3X4(CR36,0x90); // reset GE + write3X4(CR36,0x80); // enable GE + + out32(GE24,1<<7); // reset all GE pointers + out32(GE24,0); + + write3X4(CR2D,0x00); // GE Timinigs, no delays + + out32(GEB8,base); // Destination Stride / Buffer Base 0, p 133 + out32(GEBC,base); // Destination Stride / Buffer Base 1, p 133 + out32(GEC0,base); // Destination Stride / Buffer Base 2, p 133 + out32(GEC4,base); // Destination Stride / Buffer Base 3, p 133 + out32(GEC8,base); // Source Stride / Buffer Base 0, p 133 + out32(GECC,base); // Source Stride / Buffer Base 1, p 133 + out32(GED0,base); // Source Stride / Buffer Base 2, p 133 + out32(GED4,base); // Source Stride / Buffer Base 3, p 133 + out32(GE6C,0); // Pattern and Style, p 129, ok +} + +//===================================================================== +// +// Although this is a .fb_sync function that could be enabled in +// cyblafb_ops, we do not include it there. We sync immediately before +// new GE operations to improve performance. +// +//===================================================================== + +static int cyblafb_sync(struct fb_info *info) +{ + int status, i=100000; + while( ((status=in32(GE20)) & 0xFA800000) && i != 0) + i--; + + if (i == 0) { + // The timeout might be caused by disabled mmio. + // Cause: + // - bit CR39 & 1 == 0 upon return, X trident driver bug + // - kdm bug (KD_GRAPHICS not set on first switch) + // - kernel design flaw (it believes in the correctness + // of kdm/X + // So we make sure that mmio is enabled first ... + enable_mmio(); +// show_trace(NULL,&status); + i=1000000; + while( ((status=in32(GE20)) & 0xFA800000) && i != 0) + i--; + if (i == 0) { + output("GE Timeout, status: %x\n",status); + if(status & 0x80000000) + output("Bresenham Engine : Busy\n"); + if(status & 0x40000000) + output("Setup Engine : Busy\n"); + if(status & 0x20000000) + output("SP / DPE : Busy\n"); + if(status & 0x10000000) + output("Memory Interface : Busy\n"); + if(status & 0x08000000) + output("Com Lst Proc : Busy\n"); + if(status & 0x04000000) + output("Block Write : Busy\n"); + if(status & 0x02000000) + output("Command Buffer : Full\n"); + if(status & 0x01000000) + output("RESERVED : Busy\n"); + if(status & 0x00800000) + output("PCI Write Buffer : Busy\n"); + cyblafb_setup_GE(info->var.xres, + info->var.bits_per_pixel); + } + } + + return 0; +} + +//============================== +// +// Cyberblade specific fillrect +// +//============================== + +static void cyblafb_fillrect(struct fb_info * info, + const struct fb_fillrect *fr) +{ + int bpp = info->var.bits_per_pixel; + int col; + + switch (bpp) { + default: + case 8: col = fr->color; + col |= col <<8; + col |= col <<16; + break; + case 16: col = ((u32 *)(info->pseudo_palette))[fr->color]; + col |= col <<16; + break; + case 32: col = ((u32 *)(info->pseudo_palette))[fr->color]; + break; + } + + cyblafb_sync(info); + + out32(GE60,col); + out32(GE48,fr->rop ? 0x66:ROP_S); + out32(GE44,0x20000000|1<<19|1<<4|2<<2); + out32(GE08,point(fr->dx,fr->dy)); + out32(GE0C,point(fr->dx+fr->width-1,fr->dy+fr->height-1)); + +} + +//============================== +// +// Cyberblade specific copyarea +// +//============================== + +static void cyblafb_copyarea(struct fb_info *info, + const struct fb_copyarea *ca) +{ + __u32 s1,s2,d1,d2; + int direction; + + s1 = point(ca->sx,ca->sy); + s2 = point(ca->sx+ca->width-1,ca->sy+ca->height-1); + d1 = point(ca->dx,ca->dy); + d2 = point(ca->dx+ca->width-1,ca->dy+ca->height-1); + if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx))) + direction = 0; + else + direction = 2; + + cyblafb_sync(info); + + out32(GE44,0xa0000000|1<<19|1<<2|direction); + out32(GE00,direction?s2:s1); + out32(GE04,direction?s1:s2); + out32(GE08,direction?d2:d1); + out32(GE0C,direction?d1:d2); + +} + +//======================================================================= +// +// Cyberblade specific imageblit +// +// Accelerated for the most usual case, blitting 1-bit deep character +// character images. Everything else is passed to the generic imageblit. +// +//======================================================================= + +static void cyblafb_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + + u32 fgcol, bgcol; + + int i; + int bpp = info->var.bits_per_pixel; + int index = 0; + int index_end=image->height * image->width / 8; + int width_dds=image->width / 32; + int width_dbs=image->width % 32; + + if (image->depth != 1 || bpp < 8 || bpp > 32 || bpp % 8 != 0 || + image->width % 8 != 0 || image->width == 0 || image->height == 0) { + cfb_imageblit(info,image); + return; + } + + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + fgcol = ((u32*)(info->pseudo_palette))[image->fg_color]; + bgcol = ((u32*)(info->pseudo_palette))[image->bg_color]; + } else { + fgcol = image->fg_color; + bgcol = image->bg_color; + } + + switch (bpp) { + case 8: + fgcol |= fgcol <<8; fgcol |= fgcol <<16; + bgcol |= bgcol <<8; bgcol |= bgcol <<16; + break; + case 16: + fgcol |= fgcol <<16; + bgcol |= bgcol <<16; + break; + default: + break; + } + + cyblafb_sync(info); + + out32(GE60,fgcol); + out32(GE64,bgcol); + out32(GE44,0xa0000000 | 1<<20 | 1<<19); + out32(GE08,point(image->dx,image->dy)); + out32(GE0C,point(image->dx+image->width-1,image->dy+image->height-1)); + + while(index < index_end) { + for(i=0;i<width_dds;i++) { + out32(GE9C,*((u32*) ((u32)image->data + index))); + index+=4; + } + switch(width_dbs) { + case 0: break; + case 8: out32(GE9C,*((u8*)((u32)image->data+index))); + index+=1; + break; + case 16: out32(GE9C,*((u16*)((u32)image->data+index))); + index+=2; + break; + case 24: out32(GE9C,(u32)(*((u16*)((u32)image->data+index))) | + (u32)(*((u8*)((u32)image->data+index+2)))<<16); + index+=3; + break; + } + } +} + +//========================================================== +// +// Check if video mode is acceptable. We change var->??? if +// video mode is slightly off or return error otherwise. +// info->??? must not be changed! +// +//========================================================== + +static int cyblafb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int bpp = var->bits_per_pixel; + int s,t,maxvyres; + + // + // we try to support 8, 16, 24 and 32 bpp modes, + // default to 8 + // + // there is a 24 bpp mode, but for now we change requests to 32 bpp + // (This is what tridentfb does ... will be changed in the future) + // + // + if ( bpp % 8 != 0 || bpp < 8 || bpp >32) + bpp = 8; + if (bpp == 24 ) + bpp = var->bits_per_pixel = 32; + + // + // interlaced modes are broken, fail if one is requested + // + if (var->vmode & FB_VMODE_INTERLACED) + return -EINVAL; + + // + // fail if requested resolution is higher than physical + // flatpanel resolution + // + if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex) + return -EINVAL; + + // + // xres != xres_virtual is broken, fail if such an + // unusual mode is requested + // + if (var->xres != var->xres_virtual) + return -EINVAL; + + // + // we do not allow vclk to exceed 230 MHz + // + if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000) + return -EINVAL; + + // + // calc max yres_virtual that would fit in memory + // and max yres_virtual that could be used for scrolling + // and use minimum of the results as maxvyres + // + // adjust vyres_virtual to maxvyres if necessary + // fail if requested yres is bigger than maxvyres + // + s = (0x1fffff / (var->xres * bpp/8)) + var->yres; + t = info->fix.smem_len / (var->xres * bpp/8); + maxvyres = t < s ? t : s; + if (maxvyres < var->yres_virtual) + var->yres_virtual=maxvyres; + if (maxvyres < var->yres) + return -EINVAL; + + switch (bpp) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 6; + var->green.length = 6; + var->blue.length = 6; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + break; + default: + return -EINVAL; + } + + return 0; + +} + +//===================================================================== +// +// Pan the display +// +// The datasheets defines crt start address to be 20 bits wide and +// to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is +// CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use +// it, so it is also safe to be used here. BTW: datasheet CR0E on page +// 90 really is CR1E, the real CRE is documented on page 72. +// +//===================================================================== + +static int cyblafb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + unsigned int offset; + + offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32; + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + write3X4(CR0D,offset & 0xFF); + write3X4(CR0C,(offset & 0xFF00) >> 8); + write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11)); + write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17)); + write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15)); + + return 0; +} + +//============================================ +// +// This will really help in case of a bug ... +// dump most gaphics core registers. +// +//============================================ + +static void regdump(struct cyblafb_par *par) +{ + int i; + + if (verbosity < 2) + return; + + printk("\n"); + for(i=0; i<=0xff; i++) { + outb(i,0x3d4); + printk("CR%02x=%02x ",i,inb(0x3d5)); + if (i%16==15) + printk("\n"); + } + + outb(0x30,0x3ce); + outb(inb(0x3cf) | 0x40,0x3cf); + for(i=0; i<=0x1f; i++) { + if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) { + outb(i,0x3d4); + printk("CR%02x=%02x ",i,inb(0x3d5)); + } else + printk("------- "); + if (i%16==15) + printk("\n"); + } + outb(0x30,0x3ce); + outb(inb(0x3cf) & 0xbf,0x3cf); + + printk("\n"); + for(i=0; i<=0x7f; i++) { + outb(i,0x3ce); + printk("GR%02x=%02x ",i,inb(0x3cf)); + if (i%16==15) + printk("\n"); + } + + printk("\n"); + for(i=0; i<=0xff; i++) { + outb(i,0x3c4); + printk("SR%02x=%02x ",i,inb(0x3c5)); + if (i%16==15) + printk("\n"); + } + + printk("\n"); + for(i=0; i <= 0x1F; i++) { + inb(0x3da); // next access is index! + outb(i,0x3c0); + printk("AR%02x=%02x ",i,inb(0x3c1)); + if (i%16==15) + printk("\n"); + } + printk("\n"); + + inb(0x3DA); // reset internal flag to 3c0 index + outb(0x20,0x3C0); // enable attr + + return; +} + +//====================================== +// +// Set hardware to requested video mode +// +//====================================== + +static int cyblafb_set_par(struct fb_info *info) +{ + struct cyblafb_par *par = info->par; + u32 + htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch, + vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend; + struct fb_var_screeninfo *var = &info->var; + int bpp = var->bits_per_pixel; + int i; + + if (verbosity > 0) + output("Switching to new mode: " + "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n", + var->xres,var->yres,var->xres_virtual, + var->yres_virtual,var->bits_per_pixel,var->pixclock, + var->left_margin,var->right_margin,var->upper_margin, + var->lower_margin,var->hsync_len,var->vsync_len); + + htotal = (var->xres + var->left_margin + var->right_margin + + var->hsync_len) / 8 - 5; + hdispend = var->xres/8 - 1; + hsyncstart = (var->xres + var->right_margin)/8; + hsyncend = var->hsync_len/8; + hblankstart = hdispend + 1; + hblankend = htotal + 3; // should be htotal + 5, bios does it this way + preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3); + + vtotal = var->yres + var->upper_margin + var->lower_margin + + var->vsync_len - 2; + vdispend = var->yres - 1; + vsyncstart = var->yres + var->lower_margin; + vblankstart = var->yres; + vblankend = vtotal; // should be vtotal + 2, but bios does it this way + vsyncend = var->vsync_len; + + enable_mmio(); // necessary! ... check X ... + + write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07 + + write3CE(GR30,8); + + if ((displaytype == DISPLAY_FP) && var->xres < nativex) { + + // stretch or center ? + + out8(0x3C2,0xEB); + + write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on + + if (center) { + write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80); + write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80); + } + else if (stretch) { + write3CE(GR5D,0); + write3CE(GR52,(read3CE(GR52) & 0x7C) | 1); + write3CE(GR53,(read3CE(GR53) & 0x7C) | 1); + } + + } else { + out8(0x3C2,0x2B); + write3CE(GR30,8); + } + + // + // Setup CRxx regs + // + + write3X4(CR00,htotal & 0xFF); + write3X4(CR01,hdispend & 0xFF); + write3X4(CR02,hblankstart & 0xFF); + write3X4(CR03,hblankend & 0x1F); + write3X4(CR04,hsyncstart & 0xFF); + write3X4(CR05,(hsyncend & 0x1F) | ((hblankend & 0x20)<<2)); + write3X4(CR06,vtotal & 0xFF); + write3X4(CR07,(vtotal & 0x100) >> 8 | + (vdispend & 0x100) >> 7 | + (vsyncstart & 0x100) >> 6 | + (vblankstart & 0x100) >> 5 | + 0x10 | + (vtotal & 0x200) >> 4 | + (vdispend & 0x200) >> 3 | + (vsyncstart & 0x200) >> 2); + write3X4(CR08,0); + write3X4(CR09,(vblankstart & 0x200) >> 4 | 0x40 | // FIX !!! + ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0)); + write3X4(CR0A,0); // Init to some reasonable default + write3X4(CR0B,0); // Init to some reasonable default + write3X4(CR0C,0); // Offset 0 + write3X4(CR0D,0); // Offset 0 + write3X4(CR0E,0); // Init to some reasonable default + write3X4(CR0F,0); // Init to some reasonable default + write3X4(CR10,vsyncstart & 0xFF); + write3X4(CR11,(vsyncend & 0x0F)); + write3X4(CR12,vdispend & 0xFF); + write3X4(CR13,((info->var.xres * bpp)/(4*16)) & 0xFF); + write3X4(CR14,0x40); // double word mode + write3X4(CR15,vblankstart & 0xFF); + write3X4(CR16,vblankend & 0xFF); + write3X4(CR17,0xC3); + write3X4(CR18,0xFF); + // CR19: needed for interlaced modes ... ignore it for now + write3X4(CR1A,0x07); // Arbitration Control Counter 1 + write3X4(CR1B,0x07); // Arbitration Control Counter 2 + write3X4(CR1C,0x07); // Arbitration Control Counter 3 + write3X4(CR1D,0x00); // Don't know, doesn't hurt ;-) + write3X4(CR1E,(info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80); + // CR1F: do not set, contains BIOS info about memsize + write3X4(CR20,0x20); // enabe wr buf, disable 16bit planar mode + write3X4(CR21,0x20); // enable linear memory access + // CR22: RO cpu latch readback + // CR23: ??? + // CR24: RO AR flag state + // CR25: RAMDAC rw timing, pclk buffer tristate control ???? + // CR26: ??? + write3X4(CR27,(vdispend & 0x400) >> 6 | + (vsyncstart & 0x400) >> 5 | + (vblankstart & 0x400) >> 4 | + (vtotal & 0x400) >> 3 | + 0x8); + // CR28: ??? + write3X4(CR29,(read3X4(CR29) & 0xCF) | + ((((info->var.xres * bpp) / (4*16)) & 0x300) >>4)); + write3X4(CR2A,read3X4(CR2A) | 0x40); + write3X4(CR2B,(htotal & 0x100) >> 8 | + (hdispend & 0x100) >> 7 | + // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ??? + (hsyncstart & 0x100) >> 5 | + (hblankstart & 0x100) >> 4); + // CR2C: ??? + // CR2D: initialized in cyblafb_setup_GE() + write3X4(CR2F,0x92); // conservative, better signal quality + // CR30: reserved + // CR31: reserved + // CR32: reserved + // CR33: reserved + // CR34: disabled in CR36 + // CR35: disabled in CR36 + // CR36: initialized in cyblafb_setup_GE + // CR37: i2c, ignore for now + write3X4(CR38,(bpp == 8) ? 0x00 : // + (bpp == 16) ? 0x05 : // highcolor + (bpp == 24) ? 0x29 : // packed 24bit truecolor + (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus + write3X4(CR39,0x01 | // MMIO enable + (pcirb ? 0x02 : 0) | // pci read burst enable + (pciwb ? 0x04 : 0)); // pci write burst enable + write3X4(CR55,0x1F | // pci clocks * 2 for STOP# during 1st data phase + (pcirr ? 0x40 : 0) | // pci read retry enable + (pciwr ? 0x80 : 0)); // pci write retry enable + write3X4(CR56,preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01)|2 : 0); + write3X4(CR57,preendfetch >> 8 < 2 ? preendfetch & 0xff : 0); + write3X4(CR58,0x82); // Bios does this .... don't know more + // + // Setup SRxx regs + // + write3C4(SR00,3); + write3C4(SR01,1); //set char clock 8 dots wide + write3C4(SR02,0x0F); //enable 4 maps needed in chain4 mode + write3C4(SR03,0); //no character map select + write3C4(SR04,0x0E); //memory mode: ext mem, even, chain4 + + out8(0x3C4,0x0b); + in8(0x3C5); // Set NEW mode + write3C4(SR0D,0x00); // test ... check + + set_vclk(par,(bpp==32 ? 200000000 : 100000000)/ + info->var.pixclock); //SR18,SR19 + + // + // Setup GRxx regs + // + write3CE(GR00,0x00); // test ... check + write3CE(GR01,0x00); // test ... check + write3CE(GR02,0x00); // test ... check + write3CE(GR03,0x00); // test ... check + write3CE(GR04,0x00); // test ... check + write3CE(GR05,0x40); // no CGA compat,allow 256 col + write3CE(GR06,0x05); // graphics mode + write3CE(GR07,0x0F); // planes? + write3CE(GR08,0xFF); // test ... check + write3CE(GR0F,(bpp==32)?0x1A:0x12); // div vclk by 2 if 32bpp, chain4 + write3CE(GR20,0xC0); // test ... check + write3CE(GR2F,0xA0); // PCLK = VCLK, no skew, + + // + // Setup ARxx regs + // + for(i = 0;i < 0x10;i++) // set AR00 .. AR0f + write3C0(i,i); + write3C0(AR10,0x41); // graphics mode and support 256 color modes + write3C0(AR12,0x0F); // planes + write3C0(AR13,0); // horizontal pel panning + in8(0x3DA); // reset internal flag to 3c0 index + out8(0x3C0,0x20); // enable attr + + // + // Setup hidden RAMDAC command register + // + in8(0x3C8); // these reads are + in8(0x3C6); // necessary to + in8(0x3C6); // unmask the RAMDAC + in8(0x3C6); // command reg, otherwise + in8(0x3C6); // we would write the pixelmask reg! + out8(0x3C6,(bpp == 8) ? 0x00 : // 256 colors + (bpp == 15) ? 0x10 : // + (bpp == 16) ? 0x30 : // hicolor + (bpp == 24) ? 0xD0 : // truecolor + (bpp == 32) ? 0xD0 : 0); // truecolor + in8(0x3C8); + + // + // GR31 is not mentioned in the datasheet + // + if (displaytype == DISPLAY_FP) + write3CE(GR31,(read3CE(GR31) & 0x8F) | + ((info->var.yres > 1024) ? 0x50 : + (info->var.yres > 768) ? 0x30 : + (info->var.yres > 600) ? 0x20 : + (info->var.yres > 480) ? 0x10 : 0)); + + info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_TRUECOLOR; + info->fix.line_length = info->var.xres * (bpp >> 3); + info->cmap.len = (bpp == 8) ? 256: 16; + + // + // init acceleration engine + // + cyblafb_setup_GE(info->var.xres,info->var.bits_per_pixel); + + regdump(par); + + return 0; +} + +//======================== +// +// Set one color register +// +//======================== + +static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + int bpp = info->var.bits_per_pixel; + + if (regno >= info->cmap.len) + return 1; + + if (bpp == 8) { + out8(0x3C6,0xFF); + out8(0x3C8,regno); + out8(0x3C9,red>>10); + out8(0x3C9,green>>10); + out8(0x3C9,blue>>10); + + } else if (bpp == 16) // RGB 565 + ((u32*)info->pseudo_palette)[regno] = + (red & 0xF800) | + ((green & 0xFC00) >> 5) | + ((blue & 0xF800) >> 11); + else if (bpp == 32) // ARGB 8888 + ((u32*)info->pseudo_palette)[regno] = + ((transp & 0xFF00) <<16) | + ((red & 0xFF00) << 8) | + ((green & 0xFF00)) | + ((blue & 0xFF00)>>8); + + return 0; +} + +//========================================================== +// +// Try blanking the screen. For flat panels it does nothing +// +//========================================================== + +static int cyblafb_blank(int blank_mode, struct fb_info *info) +{ + unsigned char PMCont,DPMSCont; + + if (displaytype == DISPLAY_FP) + return 0; + + out8(0x83C8,0x04); // DPMS Control + PMCont = in8(0x83C6) & 0xFC; + + DPMSCont = read3CE(GR23) & 0xFC; + + switch (blank_mode) + { + case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On + case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On + PMCont |= 0x03; + DPMSCont |= 0x00; + break; + case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On + PMCont |= 0x02; + DPMSCont |= 0x01; + break; + case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off + PMCont |= 0x02; + DPMSCont |= 0x02; + break; + case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off + PMCont |= 0x00; + DPMSCont |= 0x03; + break; + } + + write3CE(GR23,DPMSCont); + out8(0x83C8,4); + out8(0x83C6,PMCont); + // + // let fbcon do a softblank for us + // + return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; +} + +static struct fb_ops cyblafb_ops __devinitdata = { + .owner = THIS_MODULE, + .fb_setcolreg = cyblafb_setcolreg, + .fb_pan_display = cyblafb_pan_display, + .fb_blank = cyblafb_blank, + .fb_check_var = cyblafb_check_var, + .fb_set_par = cyblafb_set_par, + .fb_fillrect = cyblafb_fillrect, + .fb_copyarea= cyblafb_copyarea, + .fb_imageblit = cyblafb_imageblit, + .fb_cursor = soft_cursor, +}; + +//========================================================================== +// +// getstartupmode() decides about the inital video mode +// +// There is no reason to use modedb, a lot of video modes there would +// need altered timings to display correctly. So I decided that it is much +// better to provide a limited optimized set of modes plus the option of +// using the mode in effect at startup time (might be selected using the +// vga=??? paramter). After that the user might use fbset to select any +// mode he likes, check_var will not try to alter geometry parameters as +// it would be necessary otherwise. +// +//========================================================================== + +static int __devinit getstartupmode(struct fb_info *info) +{ + u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend, + vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend, + cr00,cr01,cr02,cr03,cr04,cr05,cr2b, + cr06,cr07,cr09,cr10,cr11,cr12,cr15,cr16,cr27, + cr38, + sr0d,sr18,sr19, + gr0f, + fi,pxclkdiv,vclkdiv,tmp,i; + + struct modus { + int xres; int yres; int vyres; int bpp; int pxclk; + int left_margin; int right_margin; int upper_margin; + int lower_margin; int hsync_len; int vsync_len; + } modedb[5] = { + { 0, 0, 8000, 0, 0, 0, 0, 0, 0, 0, 0}, + { 640, 480, 3756, 0, 0, -40, 24, 17, 0, 216, 3}, + { 800, 600, 3221, 0, 0, 96, 24, 14, 0, 136, 11}, + {1024, 768, 2815, 0, 0, 144, 24, 29, 0, 120, 3}, + {1280, 1024, 2662, 0, 0, 232, 16, 39, 0, 160, 3} + }; + + outb(0x00,0x3d4); cr00=inb(0x3d5); outb(0x01,0x3d4); cr01=inb(0x3d5); + outb(0x02,0x3d4); cr02=inb(0x3d5); outb(0x03,0x3d4); cr03=inb(0x3d5); + outb(0x04,0x3d4); cr04=inb(0x3d5); outb(0x05,0x3d4); cr05=inb(0x3d5); + outb(0x06,0x3d4); cr06=inb(0x3d5); outb(0x07,0x3d4); cr07=inb(0x3d5); + outb(0x09,0x3d4); cr09=inb(0x3d5); outb(0x10,0x3d4); cr10=inb(0x3d5); + outb(0x11,0x3d4); cr11=inb(0x3d5); outb(0x12,0x3d4); cr12=inb(0x3d5); + outb(0x15,0x3d4); cr15=inb(0x3d5); outb(0x16,0x3d4); cr16=inb(0x3d5); + outb(0x27,0x3d4); cr27=inb(0x3d5); outb(0x2b,0x3d4); cr2b=inb(0x3d5); + outb(0x38,0x3d4); cr38=inb(0x3d5); outb(0x0b,0x3c4); inb(0x3c5); + outb(0x0d,0x3c4); sr0d=inb(0x3c5); outb(0x18,0x3c4); sr18=inb(0x3c5); + outb(0x19,0x3c4); sr19=inb(0x3c5); outb(0x0f,0x3ce); gr0f=inb(0x3cf); + + htotal = cr00 | (cr2b & 0x01) << 8; + hdispend = cr01 | (cr2b & 0x02) << 7; + hblankstart = cr02 | (cr2b & 0x10) << 4; + hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2; + hsyncstart = cr04 | (cr2b & 0x08) << 5; + hsyncend = cr05 & 0x1f; + + modedb[0].xres = hblankstart * 8; + modedb[0].hsync_len = hsyncend * 8; + modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres; + modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres - + modedb[0].right_margin - modedb[0].hsync_len; + + vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4 + | (cr27 & 0x80) << 3; + vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3 + | (cr27 & 0x10) << 6; + vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2 + | (cr27 & 0x20) << 5; + vsyncend = cr11 & 0x0f; + vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4 + | (cr27 & 0x40) << 4; + vblankend = cr16; + + modedb[0].yres = vdispend + 1; + modedb[0].vsync_len = vsyncend; + modedb[0].lower_margin = vsyncstart - modedb[0].yres; + modedb[0].upper_margin = vtotal - modedb[0].yres - + modedb[0].lower_margin - modedb[0].vsync_len + 2; + + tmp = cr38 & 0x3c; + modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 : + tmp == 8 ? 32 : 8; + + fi = ((5864727*(sr18+8))/(((sr19&0x3f)+2)*(1<<((sr19&0xc0)>>6))))>>12; + pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1; + tmp = sr0d & 0x06; + vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 ! + modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi; + + if (verbosity > 0) + output("detected startup mode: " + "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n", + modedb[0].xres,modedb[0].yres,modedb[0].xres, + modedb[0].bpp,modedb[0].pxclk,modedb[0].left_margin, + modedb[0].right_margin,modedb[0].upper_margin, + modedb[0].lower_margin,modedb[0].hsync_len, + modedb[0].vsync_len); + + // + // We use this goto target in case of a failed check_var. No, I really + // do not want to do it in another way! + // + + tryagain: + + i = (mode == NULL) ? 0 : + !strncmp(mode,"640x480",7) ? 1 : + !strncmp(mode,"800x600",7) ? 2 : + !strncmp(mode,"1024x768",8) ? 3 : + !strncmp(mode,"1280x1024",9) ? 4 : 0; + + ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref; + + if(i==0) { + info->var.pixclock = modedb[i].pxclk; + info->var.bits_per_pixel = modedb[i].bpp; + } else { + info->var.pixclock = (100000000 / + ((modedb[i].left_margin + modedb[i].xres + + modedb[i].right_margin + modedb[i].hsync_len + ) * ( + modedb[i].upper_margin + modedb[i].yres + + modedb[i].lower_margin + modedb[i].vsync_len + ) * + ref / 10000 + )); + info->var.bits_per_pixel = bpp; + } + + info->var.left_margin = modedb[i].left_margin; + info->var.right_margin = modedb[i].right_margin; + info->var.xres = modedb[i].xres; + info->var.xres_virtual = modedb[i].xres; + info->var.xoffset = 0; + info->var.hsync_len = modedb[i].hsync_len; + info->var.upper_margin = modedb[i].upper_margin; + info->var.yres = modedb[i].yres; + info->var.yres_virtual = modedb[i].vyres; + info->var.yoffset = 0; + info->var.lower_margin = modedb[i].lower_margin; + info->var.vsync_len = modedb[i].vsync_len; + info->var.sync = 0; + info->var.vmode = FB_VMODE_NONINTERLACED; + + if(cyblafb_check_var(&info->var,info)) { + // 640x480-8@75 should really never fail. One case would + // be fp == 1 and nativex < 640 ... give up then + if(i==1 && bpp == 8 && ref == 75){ + output("Can't find a valid mode :-(\n"); + return -EINVAL; + } + // Our detected mode is unlikely to fail. If it does, + // try 640x480-8@75 ... + if(i==0) { + mode="640x480"; + bpp=8; + ref=75; + output("Detected mode failed check_var! " + "Trying 640x480-8@75\n"); + goto tryagain; + } + // A specified video mode failed for some reason. + // Try the startup mode first + output("Specified mode '%s' failed check! " + "Falling back to startup mode.\n",mode); + mode=NULL; + goto tryagain; + } + + return 0; + +} + +//======================================================== +// +// Detect activated memory size. Undefined values require +// memsize parameter. +// +//======================================================== + +static unsigned int __devinit get_memsize(void) +{ + unsigned char tmp; + unsigned int k; + + if (memsize) + k = memsize * Kb; + else { + tmp = read3X4(CR1F) & 0x0F; + switch (tmp) { + case 0x03: k = 1 * Mb; break; + case 0x07: k = 2 * Mb; break; + case 0x0F: k = 4 * Mb; break; + case 0x04: k = 8 * Mb; break; + default: + k = 1 * Mb; + output("Unknown memory size code %x in CR1F." + " We default to 1 Mb for now, please" + " do provide a memsize parameter!\n", + tmp); + } + } + + if (verbosity > 0) + output("framebuffer size = %d Kb\n",k/Kb); + return k; +} + +//========================================================= +// +// Detect if a flat panel monitor connected to the special +// interface is active. Override is possible by fp and crt +// parameters. +// +//========================================================= + +static unsigned int __devinit get_displaytype(void) +{ + if (fp) + return DISPLAY_FP; + if (crt) + return DISPLAY_CRT; + return (read3CE(GR33) & 0x10)?DISPLAY_FP:DISPLAY_CRT; +} + +//===================================== +// +// Get native resolution of flat panel +// +//===================================== + +static int __devinit get_nativex(void) +{ + int x,y,tmp; + + if (nativex) + return nativex; + + tmp = (read3CE(GR52) >> 4) & 3; + + switch (tmp) { + case 0: x = 1280; y = 1024; break; + case 2: x = 1024; y = 768; break; + case 3: x = 800; y = 600; break; + case 4: x = 1400; y = 1050; break; + case 1: + default: x = 640; y = 480; break; + } + + if (verbosity > 0) + output("%dx%d flat panel found\n",x,y); + return x; +} + +static int __devinit cybla_pci_probe(struct pci_dev * dev, + const struct pci_device_id * id) +{ + struct fb_info *info; + struct cyblafb_par *par; + + info = framebuffer_alloc(sizeof(struct cyblafb_par),&dev->dev); + + if (!info) + goto errout_alloc; + + par = info->par; + par->ops = cyblafb_ops; + + info->fix = cyblafb_fix; + info->fbops = &par->ops; + info->fix = cyblafb_fix; + + if (pci_enable_device(dev)) { + output("could not enable device!\n"); + goto errout_enable; + } + + // might already be requested by vga console or vesafb, + // so we do care about success + request_region(0x3c0,32,"cyblafb"); + + // + // Graphics Engine Registers + // + request_region(GEBase,0x100,"cyblafb"); + + regdump(par); + + enable_mmio(); + + // setup MMIO region + info->fix.mmio_start = pci_resource_start(dev,1); + info->fix.mmio_len = 0x20000; + + if (!request_mem_region(info->fix.mmio_start, + info->fix.mmio_len,"cyblafb")) { + output("request_mem_region failed for mmio region!\n"); + goto errout_mmio_reqmem; + } + + io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); + + if (!io_virt) { + output("ioremap failed for mmio region\n"); + goto errout_mmio_remap; + } + + // setup framebuffer memory ... might already be requested + // by vesafb. Not to fail in case of an unsuccessful request + // is useful for the development cycle + info->fix.smem_start = pci_resource_start(dev,0); + info->fix.smem_len = get_memsize(); + + if (!request_mem_region(info->fix.smem_start, + info->fix.smem_len,"cyblafb")) { + output("request_mem_region failed for smem region!\n"); + if (!vesafb) + goto errout_smem_req; + } + + info->screen_base = ioremap_nocache(info->fix.smem_start, + info->fix.smem_len); + + if (!info->screen_base) { + output("ioremap failed for smem region\n"); + goto errout_smem_remap; + } + + displaytype = get_displaytype(); + + if(displaytype == DISPLAY_FP) + nativex = get_nativex(); + + // + // FBINFO_HWACCEL_YWRAP .... does not work (could be made to work?) + // FBINFO_PARTIAL_PAN_OK .... is not ok + // FBINFO_READS_FAST .... is necessary for optimal scrolling + // + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN + | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT + | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_READS_FAST; + + info->pseudo_palette = par->pseudo_pal; + + if(getstartupmode(info)) + goto errout_findmode; + + fb_alloc_cmap(&info->cmap,256,0); + + if (register_framebuffer(info)) { + output("Could not register CyBla framebuffer\n"); + goto errout_register; + } + + pci_set_drvdata(dev,info); + + // + // normal exit and error paths + // + + return 0; + + errout_register: + errout_findmode: + iounmap(info->screen_base); + errout_smem_remap: + release_mem_region(info->fix.smem_start, + info->fix.smem_len); + errout_smem_req: + iounmap(io_virt); + errout_mmio_remap: + release_mem_region(info->fix.mmio_start, + info->fix.mmio_len); + errout_mmio_reqmem: +// release_region(0x3c0,32); + errout_enable: + framebuffer_release(info); + errout_alloc: + output("CyblaFB version %s aborting init.\n",VERSION); + return -ENODEV; +} + +static void __devexit cybla_pci_remove(struct pci_dev *dev) +{ + struct fb_info *info = pci_get_drvdata(dev); + + unregister_framebuffer(info); + iounmap(io_virt); + iounmap(info->screen_base); + release_mem_region(info->fix.smem_start,info->fix.smem_len); + release_mem_region(info->fix.mmio_start,info->fix.mmio_len); + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + output("CyblaFB version %s normal exit.\n",VERSION); +} + +// +// List of boards that we are trying to support +// +static struct pci_device_id cybla_devices[] = { + {PCI_VENDOR_ID_TRIDENT,CYBERBLADEi1,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci,cybla_devices); + +static struct pci_driver cyblafb_pci_driver = { + .name = "cyblafb", + .id_table = cybla_devices, + .probe = cybla_pci_probe, + .remove = __devexit_p(cybla_pci_remove) +}; + +//============================================================= +// +// kernel command line example: +// +// video=cyblafb:1280x1024,bpp=16,ref=50 ... +// +// modprobe command line example: +// +// modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ... +// +//============================================================= + +static int __devinit cyblafb_init(void) +{ +#ifndef MODULE + char *options = NULL; + char *opt; + + if (fb_get_options("cyblafb",&options)) + return -ENODEV; + + if (options && *options) + while((opt = strsep(&options,",")) != NULL ) { + if (!*opt) continue; + else if (!strncmp(opt,"bpp=",4)) + bpp = simple_strtoul(opt+4,NULL,0); + else if (!strncmp(opt,"ref=",4)) + ref = simple_strtoul(opt+4,NULL,0); + else if (!strncmp(opt,"fp",2)) + displaytype = DISPLAY_FP; + else if (!strncmp(opt,"crt",3)) + displaytype = DISPLAY_CRT; + else if (!strncmp(opt,"nativex=",8)) + nativex = simple_strtoul(opt+8,NULL,0); + else if (!strncmp(opt,"center",6)) + center = 1; + else if (!strncmp(opt,"stretch",7)) + stretch = 1; + else if (!strncmp(opt,"pciwb=",6)) + pciwb = simple_strtoul(opt+6,NULL,0); + else if (!strncmp(opt,"pcirb=",6)) + pcirb = simple_strtoul(opt+6,NULL,0); + else if (!strncmp(opt,"pciwr=",6)) + pciwr = simple_strtoul(opt+6,NULL,0); + else if (!strncmp(opt,"pcirr=",6)) + pcirr = simple_strtoul(opt+6,NULL,0); + else if (!strncmp(opt,"memsize=",8)) + memsize = simple_strtoul(opt+8,NULL,0); + else if (!strncmp(opt,"verbosity=",10)) + verbosity = simple_strtoul(opt+10,NULL,0); + else if (!strncmp(opt,"vesafb",6)) + vesafb = 1; + else + mode = opt; + } +#endif + output("CyblaFB version %s initializing\n",VERSION); + return pci_module_init(&cyblafb_pci_driver); +} + +static void __exit cyblafb_exit(void) +{ + pci_unregister_driver(&cyblafb_pci_driver); +} + +module_init(cyblafb_init); +module_exit(cyblafb_exit); + +MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>"); +MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 698ca9232e736..81a6d9f188cf7 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -1061,6 +1061,11 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de chip_id = id->device; + if(chip_id == CYBERBLADEi1) + output("*** Please do use cyblafb, Cyberblade/i1 support " + "will soon be removed from tridentfb!\n"); + + /* If PCI id is 0x9660 then further detect chip type */ if (chip_id == TGUI9660) { diff --git a/include/video/cyblafb.h b/include/video/cyblafb.h new file mode 100644 index 0000000000000..a9948232b1316 --- /dev/null +++ b/include/video/cyblafb.h @@ -0,0 +1,171 @@ + +#ifndef CYBLAFB_DEBUG +#define CYBLAFB_DEBUG 0 +#endif + +#if CYBLAFB_DEBUG +#define debug(f,a...) printk("%s:" f, __FUNCTION__ , ## a); +#else +#define debug(f,a...) +#endif + +#define output(f, a...) printk("cyblafb: " f, ## a) + +#define Kb (1024) +#define Mb (Kb*Kb) + +/* PCI IDS of supported cards temporarily here */ + +#define CYBERBLADEi1 0x8500 + +/* these defines are for 'lcd' variable */ +#define LCD_STRETCH 0 +#define LCD_CENTER 1 +#define LCD_BIOS 2 + +/* display types */ +#define DISPLAY_CRT 0 +#define DISPLAY_FP 1 + +#define ROP_S 0xCC + +#define point(x,y) ((y)<<16|(x)) + +// +// Attribute Regs, ARxx, 3c0/3c1 +// +#define AR00 0x00 +#define AR01 0x01 +#define AR02 0x02 +#define AR03 0x03 +#define AR04 0x04 +#define AR05 0x05 +#define AR06 0x06 +#define AR07 0x07 +#define AR08 0x08 +#define AR09 0x09 +#define AR0A 0x0A +#define AR0B 0x0B +#define AR0C 0x0C +#define AR0D 0x0D +#define AR0E 0x0E +#define AR0F 0x0F +#define AR10 0x10 +#define AR12 0x12 +#define AR13 0x13 + +// +// Sequencer Regs, SRxx, 3c4/3c5 +// +#define SR00 0x00 +#define SR01 0x01 +#define SR02 0x02 +#define SR03 0x03 +#define SR04 0x04 +#define SR0D 0x0D +#define SR0E 0x0E +#define SR11 0x11 +#define SR18 0x18 +#define SR19 0x19 + +// +// +// +#define CR00 0x00 +#define CR01 0x01 +#define CR02 0x02 +#define CR03 0x03 +#define CR04 0x04 +#define CR05 0x05 +#define CR06 0x06 +#define CR07 0x07 +#define CR08 0x08 +#define CR09 0x09 +#define CR0A 0x0A +#define CR0B 0x0B +#define CR0C 0x0C +#define CR0D 0x0D +#define CR0E 0x0E +#define CR0F 0x0F +#define CR10 0x10 +#define CR11 0x11 +#define CR12 0x12 +#define CR13 0x13 +#define CR14 0x14 +#define CR15 0x15 +#define CR16 0x16 +#define CR17 0x17 +#define CR18 0x18 +#define CR19 0x19 +#define CR1A 0x1A +#define CR1B 0x1B +#define CR1C 0x1C +#define CR1D 0x1D +#define CR1E 0x1E +#define CR1F 0x1F +#define CR20 0x20 +#define CR21 0x21 +#define CR27 0x27 +#define CR29 0x29 +#define CR2A 0x2A +#define CR2B 0x2B +#define CR2D 0x2D +#define CR2F 0x2F +#define CR36 0x36 +#define CR38 0x38 +#define CR39 0x39 +#define CR3A 0x3A +#define CR55 0x55 +#define CR56 0x56 +#define CR57 0x57 +#define CR58 0x58 + +// +// +// + +#define GR00 0x01 +#define GR01 0x01 +#define GR02 0x02 +#define GR03 0x03 +#define GR04 0x04 +#define GR05 0x05 +#define GR06 0x06 +#define GR07 0x07 +#define GR08 0x08 +#define GR0F 0x0F +#define GR20 0x20 +#define GR23 0x23 +#define GR2F 0x2F +#define GR30 0x30 +#define GR31 0x31 +#define GR33 0x33 +#define GR52 0x52 +#define GR53 0x53 +#define GR5D 0x5d + + +// +// Graphics Engine +// +#define GEBase 0x2100 // could be mapped elsewhere if we like it +#define GE00 (GEBase+0x00) // source 1, p 111 +#define GE04 (GEBase+0x04) // source 2, p 111 +#define GE08 (GEBase+0x08) // destination 1, p 111 +#define GE0C (GEBase+0x0C) // destination 2, p 112 +#define GE20 (GEBase+0x20) // engine status, p 113 +#define GE24 (GEBase+0x24) // reset all GE pointers +#define GE44 (GEBase+0x44) // command register, p 126 +#define GE48 (GEBase+0x48) // raster operation, p 127 +#define GE60 (GEBase+0x60) // foreground color, p 128 +#define GE64 (GEBase+0x64) // background color, p 128 +#define GE6C (GEBase+0x6C) // Pattern and Style, p 129, ok +#define GE9C (GEBase+0x9C) // pixel engine data port, p 125 +#define GEB8 (GEBase+0xB8) // Destination Stride / Buffer Base 0, p 133 +#define GEBC (GEBase+0xBC) // Destination Stride / Buffer Base 1, p 133 +#define GEC0 (GEBase+0xC0) // Destination Stride / Buffer Base 2, p 133 +#define GEC4 (GEBase+0xC4) // Destination Stride / Buffer Base 3, p 133 +#define GEC8 (GEBase+0xC8) // Source Stride / Buffer Base 0, p 133 +#define GECC (GEBase+0xCC) // Source Stride / Buffer Base 1, p 133 +#define GED0 (GEBase+0xD0) // Source Stride / Buffer Base 2, p 133 +#define GED4 (GEBase+0xD4) // Source Stride / Buffer Base 3, p 133 -- GitLab From c5eb5c1ea919f3f717236c5d0892f9c37f19de37 Mon Sep 17 00:00:00 2001 From: Knut Petersen <Knut_Petersen@t-online.de> Date: Fri, 9 Sep 2005 13:04:59 -0700 Subject: [PATCH 236/563] [PATCH] framebuffer: bit_putcs() optimization for 8x* fonts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This trivial patch gives a performance boost to the framebuffer console Constructing the bitmaps that are given to the bitblit functions of the framebuffer drivers is time consuming. Here we avoide a call to the slow fb_pad_aligned_buffer(). The patch replaces that call with a simple but much more efficient bytewise copy. The kernel spends a significant time at this place if you use 8x* fonts. Every pixel displayed on your screen is prepared here. Some benchmark results: Displaying a file of 2000 lines with 160 characters each takes 889 ms system time using cyblafb on my system (I�m using a 1280x1024 video mode, resulting in a 160x64 character console) Displaying the same file with the enclosed patch applied to 2.6.13 only takes 760 ms system time, saving 129 ms or 14.5%. Font widths other than 8 are not affected. The advantage and correctness of this patch should be obvious. Signed-off-by: Knut Petersen <Knut_Petersen@t-online.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/console/bitblit.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 12eaf0aa87e6f..6550875ef9c53 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -114,7 +114,7 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, unsigned int scan_align = info->pixmap.scan_align - 1; unsigned int buf_align = info->pixmap.buf_align - 1; unsigned int shift_low = 0, mod = vc->vc_font.width % 8; - unsigned int shift_high = 8, pitch, cnt, size, k; + unsigned int shift_high = 8, pitch, cnt, size, i, k; unsigned int idx = vc->vc_font.width >> 3; unsigned int attribute = get_attribute(info, scr_readw(s)); struct fb_image image; @@ -175,7 +175,11 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, src = buf; } - fb_pad_aligned_buffer(dst, pitch, src, idx, image.height); + if (idx == 1) + for(i=0; i < image.height; i++) + dst[pitch*i] = src[i]; + else + fb_pad_aligned_buffer(dst, pitch, src, idx, image.height); dst += width; } } -- GitLab From 5251bffc9b4ca699993c79166adf02faf1bbc043 Mon Sep 17 00:00:00 2001 From: Daniel Burcaw <dburcaw@terrasoftsolutions.com> Date: Fri, 9 Sep 2005 13:04:59 -0700 Subject: [PATCH 237/563] [PATCH] radeonfb: Only request resources we need This patch changes radeon to request only resources 0 and 2 instead of all 3. This works around problems with some setups where BAR 1 (IO BAR) has not been assigned by the firmware since it's not used on the machine and the kernel fails to assign something to it due to the card being between a P2P bridge that was configured without an IO range at all. This typically fixes radeonfb on some Apple Xserve G5 machines Signed-off-by: Daniel Burcaw <dburcaw@terrasoftsolutions.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/aty/radeon_base.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index e7e8b52014c32..8a7c04c35a751 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -2312,19 +2312,27 @@ static int radeonfb_pci_register (struct pci_dev *pdev, rinfo->mmio_base_phys = pci_resource_start (pdev, 2); /* request the mem regions */ - ret = pci_request_regions(pdev, "radeonfb"); + ret = pci_request_region(pdev, 0, "radeonfb framebuffer"); if (ret < 0) { - printk( KERN_ERR "radeonfb (%s): cannot reserve PCI regions." - " Someone already got them?\n", pci_name(rinfo->pdev)); + printk( KERN_ERR "radeonfb (%s): cannot request region 0.\n", + pci_name(rinfo->pdev)); goto err_release_fb; } + ret = pci_request_region(pdev, 2, "radeonfb mmio"); + if (ret < 0) { + printk( KERN_ERR "radeonfb (%s): cannot request region 2.\n", + pci_name(rinfo->pdev)); + goto err_release_pci0; + } + /* map the regions */ rinfo->mmio_base = ioremap(rinfo->mmio_base_phys, RADEON_REGSIZE); if (!rinfo->mmio_base) { - printk(KERN_ERR "radeonfb (%s): cannot map MMIO\n", pci_name(rinfo->pdev)); + printk(KERN_ERR "radeonfb (%s): cannot map MMIO\n", + pci_name(rinfo->pdev)); ret = -EIO; - goto err_release_pci; + goto err_release_pci2; } rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16; @@ -2499,10 +2507,12 @@ static int radeonfb_pci_register (struct pci_dev *pdev, if (rinfo->bios_seg) radeon_unmap_ROM(rinfo, pdev); iounmap(rinfo->mmio_base); -err_release_pci: - pci_release_regions(pdev); +err_release_pci2: + pci_release_region(pdev, 2); +err_release_pci0: + pci_release_region(pdev, 0); err_release_fb: - framebuffer_release(info); + framebuffer_release(info); err_disable: pci_disable_device(pdev); err_out: @@ -2548,7 +2558,8 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) iounmap(rinfo->mmio_base); iounmap(rinfo->fb_base); - pci_release_regions(pdev); + pci_release_region(pdev, 2); + pci_release_region(pdev, 0); kfree(rinfo->mon1_EDID); kfree(rinfo->mon2_EDID); -- GitLab From 7c56075e60caaff1314decdb61b72ef576915270 Mon Sep 17 00:00:00 2001 From: Rajesh Shah <rajesh.shah@intel.com> Date: Tue, 16 Aug 2005 17:32:04 -0700 Subject: [PATCH 238/563] [PATCH] PCI: Fix PCI bus mastering enable problem in pciehp Martin Franc reported that the pciehp driver was not enabling bus master capability on his hot-plugged card. pciehprm_enable_card() was updating the PCI command register only if _HPP indicated a value for SERR or PERR that was different from the current setting. I don't have hardware that reproduces this problem, but Martin reports that this patch fixes the problem for him. Signed-off-by: Rajesh Shah <rajesh.shah@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> From rzarev@its.caltech.edu Tue Sep 6 18:29:50 2005 Date: Tue, 6 Sep 2005 13:39:32 -0700 (PDT) From: Rumen Ivanov Zarev <rzarev@its.caltech.edu> Message-Id: <200509062039.j86KdWMr014934@inky.its.caltech.edu> To: gregkh@suse.de Subject: PCI: Unhide SMBus on Compaq Evo N620c Cc: linux-kernel@vger.kernel.org Trivial patch against 2.6.13 to unhide SMBus on Compaq Evo N620c laptop using Intel 82855PM chipset. Signed-off-by: Rumen Zarev <rzarev@caltech.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/pci/quirks.c | 6 ++++++ 1 file changed, 6 insertions(+) --- gregkh-2.6.orig/drivers/pci/quirks.c 2005-09-09 10:28:55.000000000 -0700 +++ gregkh-2.6/drivers/pci/quirks.c 2005-09-09 13:51:44.000000000 -0700 @@ -876,6 +876,12 @@ static void __init asus_hides_smbus_host case 0xC00C: /* Samsung P35 notebook */ asus_hides_smbus = 1; } + } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ)) { + if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) + switch(dev->subsystem_device) { + case 0x0058: /* Compaq Evo N620c */ + asus_hides_smbus = 1; + } } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge ); --- drivers/pci/hotplug/pciehprm_acpi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/hotplug/pciehprm_acpi.c b/drivers/pci/hotplug/pciehprm_acpi.c index 305b47ec2f2cd..1406db35b0896 100644 --- a/drivers/pci/hotplug/pciehprm_acpi.c +++ b/drivers/pci/hotplug/pciehprm_acpi.c @@ -1696,15 +1696,15 @@ void pciehprm_enable_card( pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &cmd); if (card_type == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcmd); } - cmd = command = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE + command = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; + bcommand = bcmd | PCI_BRIDGE_CTL_NO_ISA; ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); if (ab) { -- GitLab From c87f883edbe969ca68c21dfa8a29674c828c22a3 Mon Sep 17 00:00:00 2001 From: Rumen Ivanov Zarev <rzarev@its.caltech.edu> Date: Tue, 6 Sep 2005 13:39:32 -0700 Subject: [PATCH 239/563] [PATCH] PCI: Unhide SMBus on Compaq Evo N620c Trivial patch against 2.6.13 to unhide SMBus on Compaq Evo N620c laptop using Intel 82855PM chipset. Signed-off-by: Rumen Zarev <rzarev@caltech.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/pci/quirks.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4f0c1bd3674a6..11ca44387cb03 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -876,6 +876,12 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0xC00C: /* Samsung P35 notebook */ asus_hides_smbus = 1; } + } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ)) { + if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) + switch(dev->subsystem_device) { + case 0x0058: /* Compaq Evo N620c */ + asus_hides_smbus = 1; + } } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge ); -- GitLab From cdb9b9f730eac4f947a2c552806a3a550bf019ef Mon Sep 17 00:00:00 2001 From: Paul Mackerras <paulus@samba.org> Date: Tue, 6 Sep 2005 09:31:03 +1000 Subject: [PATCH 240/563] [PATCH] PCI: Small rearrangement of PCI probing code This patch makes some small rearrangements of the PCI probing code in order to make it possible for arch code to set up the PCI tree without needing to duplicate code from the PCI layer unnecessarily. PPC64 will use this to set up the PCI tree from the Open Firmware device tree, which we need to do on logically-partitioned pSeries systems. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/pci/pci.h | 1 - drivers/pci/probe.c | 50 ++++++++++++++++++++++++++++++--------------- include/linux/pci.h | 3 +++ 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index d00168b1f6628..d3f3dd42240d7 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -29,7 +29,6 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; } #endif /* Functions for PCI Hotplug drivers to use */ -extern struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); extern unsigned int pci_do_scan_bus(struct pci_bus *bus); extern int pci_remove_device_safe(struct pci_dev *dev); extern unsigned char pci_max_busnr(void); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index b9c9b03919d44..35caec13023a0 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -753,27 +753,19 @@ pci_scan_device(struct pci_bus *bus, int devfn) kfree(dev); return NULL; } - device_initialize(&dev->dev); - dev->dev.release = pci_release_dev; - pci_dev_get(dev); - - dev->dev.dma_mask = &dev->dma_mask; - dev->dev.coherent_dma_mask = 0xffffffffull; return dev; } -struct pci_dev * __devinit -pci_scan_single_device(struct pci_bus *bus, int devfn) +void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) { - struct pci_dev *dev; + device_initialize(&dev->dev); + dev->dev.release = pci_release_dev; + pci_dev_get(dev); - dev = pci_scan_device(bus, devfn); - pci_scan_msi_device(dev); + dev->dev.dma_mask = &dev->dma_mask; + dev->dev.coherent_dma_mask = 0xffffffffull; - if (!dev) - return NULL; - /* Fix up broken headers */ pci_fixup_device(pci_fixup_header, dev); @@ -785,6 +777,19 @@ pci_scan_single_device(struct pci_bus *bus, int devfn) spin_lock(&pci_bus_lock); list_add_tail(&dev->bus_list, &bus->devices); spin_unlock(&pci_bus_lock); +} + +struct pci_dev * __devinit +pci_scan_single_device(struct pci_bus *bus, int devfn) +{ + struct pci_dev *dev; + + dev = pci_scan_device(bus, devfn); + if (!dev) + return NULL; + + pci_device_add(dev, bus); + pci_scan_msi_device(dev); return dev; } @@ -881,7 +886,8 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) return max; } -struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) +struct pci_bus * __devinit pci_create_bus(struct device *parent, + int bus, struct pci_ops *ops, void *sysdata) { int error; struct pci_bus *b; @@ -938,8 +944,6 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, b->resource[0] = &ioport_resource; b->resource[1] = &iomem_resource; - b->subordinate = pci_scan_child_bus(b); - return b; sys_create_link_err: @@ -957,6 +961,18 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, kfree(b); return NULL; } +EXPORT_SYMBOL_GPL(pci_create_bus); + +struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, + int bus, struct pci_ops *ops, void *sysdata) +{ + struct pci_bus *b; + + b = pci_create_bus(parent, bus, ops, sysdata); + if (b) + b->subordinate = pci_scan_child_bus(b); + return b; +} EXPORT_SYMBOL(pci_scan_bus_parented); #ifdef CONFIG_HOTPLUG diff --git a/include/linux/pci.h b/include/linux/pci.h index 609499356e074..9c7aecf0c5990 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -315,8 +315,11 @@ static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *s pci_bus_add_devices(root_bus); return root_bus; } +struct pci_bus *pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata); +struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); int pci_scan_slot(struct pci_bus *bus, int devfn); struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn); +void pci_device_add(struct pci_dev *dev, struct pci_bus *bus); unsigned int pci_scan_child_bus(struct pci_bus *bus); void pci_bus_add_device(struct pci_dev *dev); void pci_read_bridge_bases(struct pci_bus *child); -- GitLab From 96fe6a2109db29cd15b90a093c16e6cb4b19371a Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:09:58 -0700 Subject: [PATCH 241/563] [PATCH] fbdev: Add VESA Coordinated Video Timings (CVT) support The Coordinated Video Timings (CVT) is the latest standard approved by VESA concerning video timings generation. It addresses the limitation of GTF which is designed mainly for CRT displays. CRT's have a high blanking requirement (as much as 25% of the horizontal frame length) which artificially increases the pixelclock. Digital displays, on the other hand, needs to conserve the pixelclock as much as possible. The GTF also does not take into account the different aspect ratios in its calculation. The new function added is fb_find_mode_cvt(). It is called by fb_find_mode() if it recognizes a mode option string formatted for CVT. The format is: <xres>x<yres>[M][R][-<bpp>][<at-sign><refresh>][i][m] The 'M' tells the function to calculate using CVT. On it's own, it will compute a timing for CRT displays at 60Hz. If the 'R' is specified, 'reduced blanking' computation will be used, best for flatpanels. The 'i' and the 'm' is for 'interlaced mode' and 'with margins' respectively. To determine if CVT was used, check for dmesg for something like this: CVT Mode - <pix>M<n>[-R], ie: .480M3-R (800x600 reduced blanking) where: pix - product of xres and yres, in MB M - is a CVT mode n - the aspect ratio (3 - 4:3; 4 - 5:4; 9 - 16:9, 15:9; A - 16:10) -R - reduced blanking Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/fb/modedb.txt | 73 ++++++- drivers/video/Makefile | 3 +- drivers/video/fbcvt.c | 380 ++++++++++++++++++++++++++++++++++++ drivers/video/fbmem.c | 12 +- drivers/video/modedb.c | 62 +++++- include/linux/fb.h | 1 + 6 files changed, 519 insertions(+), 12 deletions(-) create mode 100644 drivers/video/fbcvt.c diff --git a/Documentation/fb/modedb.txt b/Documentation/fb/modedb.txt index e04458b319d57..4fcdb4cf4cca9 100644 --- a/Documentation/fb/modedb.txt +++ b/Documentation/fb/modedb.txt @@ -20,12 +20,83 @@ in a video= option, fbmem considers that to be a global video mode option. Valid mode specifiers (mode_option argument): - <xres>x<yres>[-<bpp>][@<refresh>] + <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] <name>[-<bpp>][@<refresh>] with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a string. Things between square brackets are optional. +If 'M' is specified in the mode_option argument (after <yres> and before +<bpp> and <refresh>, if specified) the timings will be calculated using +VESA(TM) Coordinated Video Timings instead of looking up the mode from a table. +If 'R' is specified, do a 'reduced blanking' calculation for digital displays. +If 'i' is specified, calculate for an interlaced mode. And if 'm' is +specified, add margins to the calculation (1.8% of xres rounded down to 8 +pixels and 1.8% of yres). + + Sample usage: 1024x768M@60m - CVT timing with margins + +***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** + +What is the VESA(TM) Coordinated Video Timings (CVT)? + +From the VESA(TM) Website: + + "The purpose of CVT is to provide a method for generating a consistent + and coordinated set of standard formats, display refresh rates, and + timing specifications for computer display products, both those + employing CRTs, and those using other display technologies. The + intention of CVT is to give both source and display manufacturers a + common set of tools to enable new timings to be developed in a + consistent manner that ensures greater compatibility." + +This is the third standard approved by VESA(TM) concerning video timings. The +first was the Discrete Video Timings (DVT) which is a collection of +pre-defined modes approved by VESA(TM). The second is the Generalized Timing +Formula (GTF) which is an algorithm to calculate the timings, given the +pixelclock, the horizontal sync frequency, or the vertical refresh rate. + +The GTF is limited by the fact that it is designed mainly for CRT displays. +It artificially increases the pixelclock because of its high blanking +requirement. This is inappropriate for digital display interface with its high +data rate which requires that it conserves the pixelclock as much as possible. +Also, GTF does not take into account the aspect ratio of the display. + +The CVT addresses these limitations. If used with CRT's, the formula used +is a derivation of GTF with a few modifications. If used with digital +displays, the "reduced blanking" calculation can be used. + +From the framebuffer subsystem perspective, new formats need not be added +to the global mode database whenever a new mode is released by display +manufacturers. Specifying for CVT will work for most, if not all, relatively +new CRT displays and probably with most flatpanels, if 'reduced blanking' +calculation is specified. (The CVT compatibility of the display can be +determined from its EDID. The version 1.3 of the EDID has extra 128-byte +blocks where additional timing information is placed. As of this time, there +is no support yet in the layer to parse this additional blocks.) + +CVT also introduced a new naming convention (should be seen from dmesg output): + + <pix>M<a>[-R] + + where: pix = total amount of pixels in MB (xres x yres) + M = always present + a = aspect ratio (3 - 4:3; 4 - 5:4; 9 - 15:9, 16:9; A - 16:10) + -R = reduced blanking + + example: .48M3-R - 800x600 with reduced blanking + +Note: VESA(TM) has restrictions on what is a standard CVT timing: + + - aspect ratio can only be one of the above values + - acceptable refresh rates are 50, 60, 70 or 85 Hz only + - if reduced blanking, the refresh rate must be at 60Hz + +If one of the above are not satisfied, the kernel will print a warning but the +timings will still be calculated. + +***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** oOo ***** + To find a suitable video mode, you just call int __init fb_find_mode(struct fb_var_screeninfo *var, diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 8478d217aaf07..4e7d8d27b9136 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -9,7 +9,8 @@ obj-$(CONFIG_LOGO) += logo/ obj-$(CONFIG_SYSFS) += backlight/ obj-$(CONFIG_FB) += fb.o -fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o modedb.o +fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ + modedb.o fbcvt.o fb-objs := $(fb-y) obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o diff --git a/drivers/video/fbcvt.c b/drivers/video/fbcvt.c new file mode 100644 index 0000000000000..cfa61b512de0a --- /dev/null +++ b/drivers/video/fbcvt.c @@ -0,0 +1,380 @@ +/* + * linux/drivers/video/fbcvt.c - VESA(TM) Coordinated Video Timings + * + * Copyright (C) 2005 Antonino Daplas <adaplas@pol.net> + * + * Based from the VESA(TM) Coordinated Video Timing Generator by + * Graham Loveridge April 9, 2003 available at + * http://www.vesa.org/public/CVT/CVTd6r1.xls + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ +#include <linux/fb.h> + +#define FB_CVT_CELLSIZE 8 +#define FB_CVT_GTF_C 40 +#define FB_CVT_GTF_J 20 +#define FB_CVT_GTF_K 128 +#define FB_CVT_GTF_M 600 +#define FB_CVT_MIN_VSYNC_BP 550 +#define FB_CVT_MIN_VPORCH 3 +#define FB_CVT_MIN_BPORCH 6 + +#define FB_CVT_RB_MIN_VBLANK 460 +#define FB_CVT_RB_HBLANK 160 +#define FB_CVT_RB_V_FPORCH 3 + +#define FB_CVT_FLAG_REDUCED_BLANK 1 +#define FB_CVT_FLAG_MARGINS 2 +#define FB_CVT_FLAG_INTERLACED 4 + +struct fb_cvt_data { + u32 xres; + u32 yres; + u32 refresh; + u32 f_refresh; + u32 pixclock; + u32 hperiod; + u32 hblank; + u32 hfreq; + u32 htotal; + u32 vtotal; + u32 vsync; + u32 hsync; + u32 h_front_porch; + u32 h_back_porch; + u32 v_front_porch; + u32 v_back_porch; + u32 h_margin; + u32 v_margin; + u32 interlace; + u32 aspect_ratio; + u32 active_pixels; + u32 flags; + u32 status; +}; + +static int fb_cvt_vbi_tab[] = { + 4, /* 4:3 */ + 5, /* 16:9 */ + 6, /* 16:10 */ + 7, /* 5:4 */ + 7, /* 15:9 */ + 8, /* reserved */ + 9, /* reserved */ + 10 /* custom */ +}; + +/* returns hperiod * 1000 */ +static u32 fb_cvt_hperiod(struct fb_cvt_data *cvt) +{ + u32 num = 1000000000/cvt->f_refresh; + u32 den; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) { + num -= FB_CVT_RB_MIN_VBLANK * 1000; + den = 2 * (cvt->yres/cvt->interlace + 2 * cvt->v_margin); + } else { + num -= FB_CVT_MIN_VSYNC_BP * 1000; + den = 2 * (cvt->yres/cvt->interlace + cvt->v_margin * 2 + + FB_CVT_MIN_VPORCH + cvt->interlace/2); + } + + return 2 * (num/den); +} + +/* returns ideal duty cycle * 1000 */ +static u32 fb_cvt_ideal_duty_cycle(struct fb_cvt_data *cvt) +{ + u32 c_prime = (FB_CVT_GTF_C - FB_CVT_GTF_J) * + (FB_CVT_GTF_K) + 256 * FB_CVT_GTF_J; + u32 m_prime = (FB_CVT_GTF_K * FB_CVT_GTF_M); + u32 h_period_est = cvt->hperiod; + + return (1000 * c_prime - ((m_prime * h_period_est)/1000))/256; +} + +static u32 fb_cvt_hblank(struct fb_cvt_data *cvt) +{ + u32 hblank = 0; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) + hblank = FB_CVT_RB_HBLANK; + else { + u32 ideal_duty_cycle = fb_cvt_ideal_duty_cycle(cvt); + u32 active_pixels = cvt->active_pixels; + + if (ideal_duty_cycle < 20000) + hblank = (active_pixels * 20000)/ + (100000 - 20000); + else { + hblank = (active_pixels * ideal_duty_cycle)/ + (100000 - ideal_duty_cycle); + } + } + + hblank &= ~((2 * FB_CVT_CELLSIZE) - 1); + + return hblank; +} + +static u32 fb_cvt_hsync(struct fb_cvt_data *cvt) +{ + u32 hsync; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) + hsync = 32; + else + hsync = (FB_CVT_CELLSIZE * cvt->htotal)/100; + + hsync &= ~(FB_CVT_CELLSIZE - 1); + return hsync; +} + +static u32 fb_cvt_vbi_lines(struct fb_cvt_data *cvt) +{ + u32 vbi_lines, min_vbi_lines, act_vbi_lines; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) { + vbi_lines = (1000 * FB_CVT_RB_MIN_VBLANK)/cvt->hperiod + 1; + min_vbi_lines = FB_CVT_RB_V_FPORCH + cvt->vsync + + FB_CVT_MIN_BPORCH; + + } else { + vbi_lines = (FB_CVT_MIN_VSYNC_BP * 1000)/cvt->hperiod + 1 + + FB_CVT_MIN_VPORCH; + min_vbi_lines = cvt->vsync + FB_CVT_MIN_BPORCH + + FB_CVT_MIN_VPORCH; + } + + if (vbi_lines < min_vbi_lines) + act_vbi_lines = min_vbi_lines; + else + act_vbi_lines = vbi_lines; + + return act_vbi_lines; +} + +static u32 fb_cvt_vtotal(struct fb_cvt_data *cvt) +{ + u32 vtotal = cvt->yres/cvt->interlace; + + vtotal += 2 * cvt->v_margin + cvt->interlace/2 + fb_cvt_vbi_lines(cvt); + vtotal |= cvt->interlace/2; + + return vtotal; +} + +static u32 fb_cvt_pixclock(struct fb_cvt_data *cvt) +{ + u32 pixclock; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) + pixclock = (cvt->f_refresh * cvt->vtotal * cvt->htotal)/1000; + else + pixclock = (cvt->htotal * 1000000)/cvt->hperiod; + + pixclock /= 250; + pixclock *= 250; + pixclock *= 1000; + + return pixclock; +} + +static u32 fb_cvt_aspect_ratio(struct fb_cvt_data *cvt) +{ + u32 xres = cvt->xres; + u32 yres = cvt->yres; + u32 aspect = -1; + + if (xres == (yres * 4)/3 && !((yres * 4) % 3)) + aspect = 0; + else if (xres == (yres * 16)/9 && !((yres * 16) % 9)) + aspect = 1; + else if (xres == (yres * 16)/10 && !((yres * 16) % 10)) + aspect = 2; + else if (xres == (yres * 5)/4 && !((yres * 5) % 4)) + aspect = 3; + else if (xres == (yres * 15)/9 && !((yres * 15) % 9)) + aspect = 4; + else { + printk(KERN_INFO "fbcvt: Aspect ratio not CVT " + "standard\n"); + aspect = 7; + cvt->status = 1; + } + + return aspect; +} + +static void fb_cvt_print_name(struct fb_cvt_data *cvt) +{ + u32 pixcount, pixcount_mod; + int cnt = 255, offset = 0, read = 0; + u8 *buf = kmalloc(256, GFP_KERNEL); + + if (!buf) + return; + + memset(buf, 0, 256); + pixcount = (cvt->xres * (cvt->yres/cvt->interlace))/1000000; + pixcount_mod = (cvt->xres * (cvt->yres/cvt->interlace)) % 1000000; + pixcount_mod /= 1000; + + read = snprintf(buf+offset, cnt, "fbcvt: %dx%d@%d: CVT Name - ", + cvt->xres, cvt->yres, cvt->refresh); + offset += read; + cnt -= read; + + if (cvt->status) + snprintf(buf+offset, cnt, "Not a CVT standard - %d.%03d Mega " + "Pixel Image\n", pixcount, pixcount_mod); + else { + if (pixcount) { + read = snprintf(buf+offset, cnt, "%d", pixcount); + cnt -= read; + offset += read; + } + + read = snprintf(buf+offset, cnt, ".%03dM", pixcount_mod); + cnt -= read; + offset += read; + + if (cvt->aspect_ratio == 0) + read = snprintf(buf+offset, cnt, "3"); + else if (cvt->aspect_ratio == 3) + read = snprintf(buf+offset, cnt, "4"); + else if (cvt->aspect_ratio == 1 || cvt->aspect_ratio == 4) + read = snprintf(buf+offset, cnt, "9"); + else if (cvt->aspect_ratio == 2) + read = snprintf(buf+offset, cnt, "A"); + else + read = 0; + cnt -= read; + offset += read; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) { + read = snprintf(buf+offset, cnt, "-R"); + cnt -= read; + offset += read; + } + } + + printk(KERN_INFO "%s\n", buf); + kfree(buf); +} + +static void fb_cvt_convert_to_mode(struct fb_cvt_data *cvt, + struct fb_videomode *mode) +{ + mode->refresh = cvt->f_refresh; + mode->pixclock = KHZ2PICOS(cvt->pixclock/1000); + mode->left_margin = cvt->h_front_porch; + mode->right_margin = cvt->h_back_porch; + mode->hsync_len = cvt->hsync; + mode->upper_margin = cvt->v_front_porch; + mode->lower_margin = cvt->v_back_porch; + mode->vsync_len = cvt->vsync; + + mode->sync &= ~(FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT); + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) + mode->sync |= FB_SYNC_HOR_HIGH_ACT; + else + mode->sync |= FB_SYNC_VERT_HIGH_ACT; +} + +/* + * fb_find_mode_cvt - calculate mode using VESA(TM) CVT + * @mode: pointer to fb_videomode; xres, yres, refresh and vmode must be + * pre-filled with the desired values + * @margins: add margin to calculation (1.8% of xres and yres) + * @rb: compute with reduced blanking (for flatpanels) + * + * RETURNS: + * 0 for success + * @mode is filled with computed values. If interlaced, the refresh field + * will be filled with the field rate (2x the frame rate) + * + * DESCRIPTION: + * Computes video timings using VESA(TM) Coordinated Video Timings + */ +int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb) +{ + struct fb_cvt_data cvt; + + memset(&cvt, 0, sizeof(cvt)); + + if (margins) + cvt.flags |= FB_CVT_FLAG_MARGINS; + + if (rb) + cvt.flags |= FB_CVT_FLAG_REDUCED_BLANK; + + if (mode->vmode & FB_VMODE_INTERLACED) + cvt.flags |= FB_CVT_FLAG_INTERLACED; + + cvt.xres = mode->xres; + cvt.yres = mode->yres; + cvt.refresh = mode->refresh; + cvt.f_refresh = cvt.refresh; + cvt.interlace = 1; + + if (!cvt.xres || !cvt.yres || !cvt.refresh) { + printk(KERN_INFO "fbcvt: Invalid input parameters\n"); + return 1; + } + + if (!(cvt.refresh == 50 || cvt.refresh == 60 || cvt.refresh == 70 || + cvt.refresh == 85)) { + printk(KERN_INFO "fbcvt: Refresh rate not CVT " + "standard\n"); + cvt.status = 1; + } + + cvt.xres &= ~(FB_CVT_CELLSIZE - 1); + + if (cvt.flags & FB_CVT_FLAG_INTERLACED) { + cvt.interlace = 2; + cvt.f_refresh *= 2; + } + + if (cvt.flags & FB_CVT_FLAG_REDUCED_BLANK) { + if (cvt.refresh != 60) { + printk(KERN_INFO "fbcvt: 60Hz refresh rate " + "advised for reduced blanking\n"); + cvt.status = 1; + } + } + + if (cvt.flags & FB_CVT_FLAG_MARGINS) { + cvt.h_margin = (cvt.xres * 18)/1000; + cvt.h_margin &= ~(FB_CVT_CELLSIZE - 1); + cvt.v_margin = ((cvt.yres/cvt.interlace)* 18)/1000; + } + + cvt.aspect_ratio = fb_cvt_aspect_ratio(&cvt); + cvt.active_pixels = cvt.xres + 2 * cvt.h_margin; + cvt.hperiod = fb_cvt_hperiod(&cvt); + cvt.vsync = fb_cvt_vbi_tab[cvt.aspect_ratio]; + cvt.vtotal = fb_cvt_vtotal(&cvt); + cvt.hblank = fb_cvt_hblank(&cvt); + cvt.htotal = cvt.active_pixels + cvt.hblank; + cvt.hsync = fb_cvt_hsync(&cvt); + cvt.pixclock = fb_cvt_pixclock(&cvt); + cvt.hfreq = cvt.pixclock/cvt.htotal; + cvt.h_back_porch = cvt.hblank/2 + cvt.h_margin; + cvt.h_front_porch = cvt.hblank - cvt.hsync - cvt.h_back_porch + + 2 * cvt.h_margin; + cvt.v_back_porch = 3 + cvt.v_margin; + cvt.v_front_porch = cvt.vtotal - cvt.yres/cvt.interlace - + cvt.v_back_porch - cvt.vsync; + fb_cvt_print_name(&cvt); + fb_cvt_convert_to_mode(&cvt, mode); + + return 0; +} +EXPORT_SYMBOL(fb_find_mode_cvt); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index a815f5e2fcb5b..71b55070bdb97 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1029,6 +1029,7 @@ register_framebuffer(struct fb_info *fb_info) { int i; struct fb_event event; + struct fb_videomode mode; if (num_registered_fb == FB_MAX) return -ENXIO; @@ -1059,16 +1060,11 @@ register_framebuffer(struct fb_info *fb_info) } fb_info->pixmap.offset = 0; - if (!fb_info->modelist.prev || - !fb_info->modelist.next || - list_empty(&fb_info->modelist)) { - struct fb_videomode mode; - + if (!fb_info->modelist.prev || !fb_info->modelist.next) INIT_LIST_HEAD(&fb_info->modelist); - fb_var_to_videomode(&mode, &fb_info->var); - fb_add_videomode(&mode, &fb_info->modelist); - } + fb_var_to_videomode(&mode, &fb_info->var); + fb_add_videomode(&mode, &fb_info->modelist); registered_fb[i] = fb_info; devfs_mk_cdev(MKDEV(FB_MAJOR, i), diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 3edc9f49344b6..47516c44a390a 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -456,12 +456,22 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, * * Valid mode specifiers for @mode_option: * - * <xres>x<yres>[-<bpp>][@<refresh>] or + * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or * <name>[-<bpp>][@<refresh>] * * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and * <name> a string. * + * If 'M' is present after yres (and before refresh/bpp if present), + * the function will compute the timings using VESA(tm) Coordinated + * Video Timings (CVT). If 'R' is present after 'M', will compute with + * reduced blanking (for flatpanels). If 'i' is present, compute + * interlaced mode. If 'm' is present, add margins equal to 1.8% + * of xres rounded down to 8 pixels, and 1.8% of yres. The char + * 'i' and 'm' must be after 'M' and 'R'. Example: + * + * 1024x768MR-8@60m - Reduced blank with margins at 60Hz. + * * NOTE: The passed struct @var is _not_ cleared! This allows you * to supply values for e.g. the grayscale and accel_flags fields. * @@ -495,7 +505,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, unsigned int namelen = strlen(name); int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; - int yres_specified = 0; + int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; u32 best, diff; for (i = namelen-1; i >= 0; i--) { @@ -506,6 +516,8 @@ int fb_find_mode(struct fb_var_screeninfo *var, !yres_specified) { refresh = my_atoi(&name[i+1]); refresh_specified = 1; + if (cvt || rb) + cvt = 0; } else goto done; break; @@ -514,6 +526,8 @@ int fb_find_mode(struct fb_var_screeninfo *var, if (!bpp_specified && !yres_specified) { bpp = my_atoi(&name[i+1]); bpp_specified = 1; + if (cvt || rb) + cvt = 0; } else goto done; break; @@ -526,6 +540,22 @@ int fb_find_mode(struct fb_var_screeninfo *var, break; case '0'...'9': break; + case 'M': + if (!yres_specified) + cvt = 1; + break; + case 'R': + if (!cvt) + rb = 1; + break; + case 'm': + if (!cvt) + margins = 1; + break; + case 'i': + if (!cvt) + interlace = 1; + break; default: goto done; } @@ -535,6 +565,34 @@ int fb_find_mode(struct fb_var_screeninfo *var, res_specified = 1; } done: + if (cvt) { + struct fb_videomode cvt_mode; + int ret; + + DPRINTK("CVT mode %dx%d@%dHz%s%s%s\n", xres, yres, + (refresh) ? refresh : 60, (rb) ? " reduced blanking" : + "", (margins) ? " with margins" : "", (interlace) ? + " interlaced" : ""); + + cvt_mode.xres = xres; + cvt_mode.yres = yres; + cvt_mode.refresh = (refresh) ? refresh : 60; + + if (interlace) + cvt_mode.vmode |= FB_VMODE_INTERLACED; + else + cvt_mode.vmode &= ~FB_VMODE_INTERLACED; + + ret = fb_find_mode_cvt(&cvt_mode, margins, rb); + + if (!ret && !fb_try_mode(var, info, &cvt_mode, bpp)) { + DPRINTK("modedb CVT: CVT mode ok\n"); + return 1; + } + + DPRINTK("CVT mode invalid, getting mode from database\n"); + } + DPRINTK("Trying specified video mode%s %ix%i\n", refresh_specified ? "" : " (ignoring refresh rate)", xres, yres); diff --git a/include/linux/fb.h b/include/linux/fb.h index 34814a0b2378f..9a4f035e9fdc6 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -866,6 +866,7 @@ extern const unsigned char *fb_firmware_edid(struct device *device); extern void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs); extern void fb_destroy_modedb(struct fb_videomode *modedb); +extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb); /* drivers/video/modedb.c */ #define VESA_MODEDB_SIZE 34 -- GitLab From 948a95ff5efb018d08d104c283081dba6472f801 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:09:59 -0700 Subject: [PATCH 242/563] [PATCH] nvidiafb: Use CVT to get mode for digital displays If no EDID block is probed, if the display is digital and if no mode option is specified by the user, get the timings by CVT instead of using the global mode database. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/nvidia/nvidia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 32952204ce331..3620de0f252e6 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -1328,7 +1328,7 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info) char buf[16]; memset(buf, 0, 16); - snprintf(buf, 15, "%dx%d", par->fpWidth, par->fpHeight); + snprintf(buf, 15, "%dx%dMR", par->fpWidth, par->fpHeight); fb_find_mode(&nvidiafb_default_var, info, buf, specs->modedb, specs->modedb_len, &modedb, 8); } -- GitLab From c52890cc366429798b3c97266d0a377810e08400 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:09:59 -0700 Subject: [PATCH 243/563] [PATCH] savagefb: Make mode_option available when compiled as a module Make "mode_option" available when compiled as a module. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/savage/savagefb_driver.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 86522888e0aa5..b5ca3ef8271f3 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -2383,3 +2383,6 @@ static int __init savagefb_init(void) module_init(savagefb_init); module_exit(savage_done); + +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Specify initial video mode"); -- GitLab From 88fb2c6efba8d9e941e9fb61f37dbeafc869fd75 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:10:00 -0700 Subject: [PATCH 244/563] [PATCH] fbcon: Stop cursor timer if console is inactive If console is blanked or in KD_GRAPHICS mode, delete cursor timer. No sense flashing the cursor when there's nothing to be seen. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/console/fbcon.c | 92 +++++++++++++++++++---------------- drivers/video/console/fbcon.h | 3 +- 2 files changed, 52 insertions(+), 43 deletions(-) diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index bb4ea50b54a33..2e93224d2d550 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -331,6 +331,35 @@ static void cursor_timer_handler(unsigned long dev_addr) mod_timer(&ops->cursor_timer, jiffies + HZ/5); } +static void fbcon_add_cursor_timer(struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + + if ((!info->queue.func || info->queue.func == fb_flashcursor) && + !(ops->flags & FBCON_FLAGS_CURSOR_TIMER)) { + if (!info->queue.func) + INIT_WORK(&info->queue, fb_flashcursor, info); + + init_timer(&ops->cursor_timer); + ops->cursor_timer.function = cursor_timer_handler; + ops->cursor_timer.expires = jiffies + HZ / 5; + ops->cursor_timer.data = (unsigned long ) info; + add_timer(&ops->cursor_timer); + ops->flags |= FBCON_FLAGS_CURSOR_TIMER; + } +} + +static void fbcon_del_cursor_timer(struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + + if (info->queue.func == fb_flashcursor && + ops->flags & FBCON_FLAGS_CURSOR_TIMER) { + del_timer_sync(&ops->cursor_timer); + ops->flags &= ~FBCON_FLAGS_CURSOR_TIMER; + } +} + #ifndef MODULE static int __init fb_console_setup(char *this_opt) { @@ -583,9 +612,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, } if (!err) { - if (oldinfo->queue.func == fb_flashcursor) - del_timer_sync(&ops->cursor_timer); - + fbcon_del_cursor_timer(oldinfo); kfree(ops->cursor_state.mask); kfree(ops->cursor_data); kfree(oldinfo->fbcon_par); @@ -596,22 +623,6 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, return err; } -static void con2fb_init_newinfo(struct fb_info *info) -{ - if (!info->queue.func || info->queue.func == fb_flashcursor) { - struct fbcon_ops *ops = info->fbcon_par; - - if (!info->queue.func) - INIT_WORK(&info->queue, fb_flashcursor, info); - - init_timer(&ops->cursor_timer); - ops->cursor_timer.function = cursor_timer_handler; - ops->cursor_timer.expires = jiffies + HZ / 5; - ops->cursor_timer.data = (unsigned long ) info; - add_timer(&ops->cursor_timer); - } -} - static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, int unit, int show_logo) { @@ -695,7 +706,7 @@ static int set_con2fb_map(int unit, int newidx, int user) logo_shown != FBCON_LOGO_DONTSHOW); if (!found) - con2fb_init_newinfo(info); + fbcon_add_cursor_timer(info); con2fb_map_boot[unit] = newidx; con2fb_init_display(vc, info, unit, show_logo); } @@ -898,18 +909,7 @@ static const char *fbcon_startup(void) } #endif /* CONFIG_MAC */ - /* Initialize the work queue. If the driver provides its - * own work queue this means it will use something besides - * default timer to flash the cursor. */ - if (!info->queue.func) { - INIT_WORK(&info->queue, fb_flashcursor, info); - - init_timer(&ops->cursor_timer); - ops->cursor_timer.function = cursor_timer_handler; - ops->cursor_timer.expires = jiffies + HZ / 5; - ops->cursor_timer.data = (unsigned long ) info; - add_timer(&ops->cursor_timer); - } + fbcon_add_cursor_timer(info); return display_desc; } @@ -1923,7 +1923,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, static int fbcon_switch(struct vc_data *vc) { - struct fb_info *info; + struct fb_info *info, *old_info = NULL; struct display *p = &fb_display[vc->vc_num]; struct fb_var_screeninfo var; int i, prev_console; @@ -1956,7 +1956,8 @@ static int fbcon_switch(struct vc_data *vc) } prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon; - + if (prev_console != -1) + old_info = registered_fb[con2fb_map[prev_console]]; /* * FIXME: If we have multiple fbdev's loaded, we need to * update all info->currcon. Perhaps, we can place this @@ -1984,10 +1985,12 @@ static int fbcon_switch(struct vc_data *vc) info->var.yoffset = info->var.xoffset = p->yscroll = 0; fb_set_var(info, &var); - if (prev_console != -1 && - registered_fb[con2fb_map[prev_console]] != info && - info->fbops->fb_set_par) - info->fbops->fb_set_par(info); + if (old_info != NULL && old_info != info) { + if (info->fbops->fb_set_par) + info->fbops->fb_set_par(info); + fbcon_del_cursor_timer(old_info); + fbcon_add_cursor_timer(info); + } set_blitting_type(vc, info, p); ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1; @@ -2073,11 +2076,16 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) fbcon_generic_blank(vc, info, blank); } - if (!blank) - update_screen(vc); - } + if (!blank) + update_screen(vc); + } + + if (!blank) + fbcon_add_cursor_timer(info); + else + fbcon_del_cursor_timer(info); - return 0; + return 0; } static void fbcon_free_font(struct display *p) diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 5d377860bce28..08befafe11d14 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -18,7 +18,8 @@ #include <asm/io.h> -#define FBCON_FLAGS_INIT 1 +#define FBCON_FLAGS_INIT 1 +#define FBCON_FLAGS_CURSOR_TIMER 2 /* * This is the interface between the low-level console driver and the -- GitLab From 7c1cd6fd5efeb95603e37f35b5da293b452d8b64 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:10:01 -0700 Subject: [PATCH 245/563] [PATCH] nvidiafb: Fixed mirrored characters in big endian machines nvidiafb_imageblit converts the bitdata stream from big_endian to little endian. This produces mirrored characters when machine is big_endian. Do not endian convert on big endian machines. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/nvidia/nv_local.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/video/nvidia/nv_local.h b/drivers/video/nvidia/nv_local.h index 9da320986f4c9..afee284fc73c9 100644 --- a/drivers/video/nvidia/nv_local.h +++ b/drivers/video/nvidia/nv_local.h @@ -95,6 +95,7 @@ #define READ_GET(par) (NV_RD32(&(par)->FIFO[0x0011], 0) >> 2) +#ifdef __LITTLE_ENDIAN #define reverse_order(l) \ do { \ u8 *a = (u8 *)(l); \ @@ -103,5 +104,8 @@ do { \ *a = byte_rev[*a], a++; \ *a = byte_rev[*a]; \ } while(0) +#else +#define reverse_order(l) +#endif /* __LITTLE_ENDIAN */ #endif /* __NV_LOCAL_H__ */ -- GitLab From 61ab7903b8cd772d3bfb28bc26d02c599cfb0e5b Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:10:02 -0700 Subject: [PATCH 246/563] [PATCH] fbdev: Initialize var structure in calc_mode_timings The var structure in calc_mode_timings is not properly initialized (zero set) which leads to undefined behavior when it is passed to fb_get_mode(). Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/fbmon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 791bec3d672af..713226cdf3c6b 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -314,11 +314,13 @@ static int edid_is_monitor_block(unsigned char *block) return 0; } -static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode) +static void calc_mode_timings(int xres, int yres, int refresh, + struct fb_videomode *mode) { struct fb_var_screeninfo var; struct fb_info info; + memset(&var, 0, sizeof(struct fb_var_screeninfo)); var.xres = xres; var.yres = yres; fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, -- GitLab From ba44cd2d8abc3271a608b42cdbf55e1e575e2ba5 Mon Sep 17 00:00:00 2001 From: Richard Purdie <rpurdie@rpsys.net> Date: Fri, 9 Sep 2005 13:10:03 -0700 Subject: [PATCH 247/563] [PATCH] pxafb: Add hsync time reporting hook To solve touchscreen interference problems devices like the Sharp Zaurus SL-C3000 need to know the length of the horitzontal sync pulses. This patch adds a hook to pxafb so the touchscreen driver can function correctly. Signed-Off-By: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/pxafb.c | 32 ++++++++++++++++++++++++++++++++ drivers/video/pxafb.h | 2 ++ include/asm-arm/arch-pxa/pxafb.h | 1 + 3 files changed, 35 insertions(+) diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 30112816420c7..34d4dcc0320ac 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -467,6 +467,36 @@ static inline unsigned int get_pcd(unsigned int pixclock) return (unsigned int)pcd; } +/* + * Some touchscreens need hsync information from the video driver to + * function correctly. We export it here. + */ +static inline void set_hsync_time(struct pxafb_info *fbi, unsigned int pcd) +{ + unsigned long long htime; + + if ((pcd == 0) || (fbi->fb.var.hsync_len == 0)) { + fbi->hsync_time=0; + return; + } + + htime = (unsigned long long)get_lcdclk_frequency_10khz() * 10000; + do_div(htime, pcd * fbi->fb.var.hsync_len); + fbi->hsync_time = htime; +} + +unsigned long pxafb_get_hsync_time(struct device *dev) +{ + struct pxafb_info *fbi = dev_get_drvdata(dev); + + /* If display is blanked/suspended, hsync isn't active */ + if (!fbi || (fbi->state != C_ENABLE)) + return 0; + + return fbi->hsync_time; +} +EXPORT_SYMBOL(pxafb_get_hsync_time); + /* * pxafb_activate_var(): * Configures LCD Controller based on entries in var parameter. Settings are @@ -631,6 +661,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info * fbi->reg_lccr1 = new_regs.lccr1; fbi->reg_lccr2 = new_regs.lccr2; fbi->reg_lccr3 = new_regs.lccr3; + set_hsync_time(fbi, pcd); local_irq_restore(flags); /* @@ -907,6 +938,7 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data) case CPUFREQ_POSTCHANGE: pcd = get_pcd(fbi->fb.var.pixclock); + set_hsync_time(fbi, pcd); fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE); break; diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h index de15fec5f82f5..22c00be786a8e 100644 --- a/drivers/video/pxafb.h +++ b/drivers/video/pxafb.h @@ -83,6 +83,8 @@ struct pxafb_info { u_int reg_lccr2; u_int reg_lccr3; + unsigned long hsync_time; + volatile u_char state; volatile u_char task_state; struct semaphore ctrlr_sem; diff --git a/include/asm-arm/arch-pxa/pxafb.h b/include/asm-arm/arch-pxa/pxafb.h index 27d71e9d413b9..21c0e16dce5fe 100644 --- a/include/asm-arm/arch-pxa/pxafb.h +++ b/include/asm-arm/arch-pxa/pxafb.h @@ -66,3 +66,4 @@ struct pxafb_mach_info { }; void set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info); +unsigned long pxafb_get_hsync_time(struct device *dev); -- GitLab From 829e79b680210c4f4de435af6e1f90451922fc7d Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:10:04 -0700 Subject: [PATCH 248/563] [PATCH] fbcon: Break up bit_putcs into its component functions The function bit_putcs() in drivers/video/console/bitblit.c is becoming large. Break it up into its component functions (bit_putcs_unaligned and bit_putcs_aligned). Incorporated fb_pad_aligned_buffer() optimization by Roman Zippel. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/console/bitblit.c | 150 ++++++++++++++++++++------------ drivers/video/fbmem.c | 10 +-- include/linux/fb.h | 15 ++++ 3 files changed, 109 insertions(+), 66 deletions(-) diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 6550875ef9c53..9f70e512b88bf 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -103,42 +103,104 @@ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, info->fbops->fb_fillrect(info, ®ion); } +static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info, + const u16 *s, u32 attr, u32 cnt, + u32 d_pitch, u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, u8 *dst) +{ + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 idx = vc->vc_font.width >> 3; + u8 *src; + + while (cnt--) { + src = vc->vc_font.data + (scr_readw(s++)& + charmask)*cellsize; + + if (attr) { + update_attr(buf, src, attr, vc); + src = buf; + } + + if (likely(idx == 1)) + __fb_pad_aligned_buffer(dst, d_pitch, src, idx, + image->height); + else + fb_pad_aligned_buffer(dst, d_pitch, src, idx, + image->height); + + dst += s_pitch; + } + + info->fbops->fb_imageblit(info, image); +} + +static inline void bit_putcs_unaligned(struct vc_data *vc, + struct fb_info *info, const u16 *s, + u32 attr, u32 cnt, u32 d_pitch, + u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, + u8 *dst) +{ + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 shift_low = 0, mod = vc->vc_font.width % 8; + u32 shift_high = 8; + u32 idx = vc->vc_font.width >> 3; + u8 *src; + + while (cnt--) { + src = vc->vc_font.data + (scr_readw(s++)& + charmask)*cellsize; + + if (attr) { + update_attr(buf, src, attr, vc); + src = buf; + } + + fb_pad_unaligned_buffer(dst, d_pitch, src, idx, + image->height, shift_high, + shift_low, mod); + shift_low += mod; + dst += (shift_low >= 8) ? s_pitch : s_pitch - 1; + shift_low &= 7; + shift_high = 8 - shift_low; + } + + info->fbops->fb_imageblit(info, image); + +} + static void bit_putcs(struct vc_data *vc, struct fb_info *info, const unsigned short *s, int count, int yy, int xx, int fg, int bg) { - unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; - unsigned int width = (vc->vc_font.width + 7) >> 3; - unsigned int cellsize = vc->vc_font.height * width; - unsigned int maxcnt = info->pixmap.size/cellsize; - unsigned int scan_align = info->pixmap.scan_align - 1; - unsigned int buf_align = info->pixmap.buf_align - 1; - unsigned int shift_low = 0, mod = vc->vc_font.width % 8; - unsigned int shift_high = 8, pitch, cnt, size, i, k; - unsigned int idx = vc->vc_font.width >> 3; - unsigned int attribute = get_attribute(info, scr_readw(s)); struct fb_image image; - u8 *src, *dst, *buf = NULL; - - if (attribute) { - buf = kmalloc(cellsize, GFP_KERNEL); - if (!buf) - return; - } + u32 width = (vc->vc_font.width + 7)/8; + u32 cellsize = width * vc->vc_font.height; + u32 maxcnt = info->pixmap.size/cellsize; + u32 scan_align = info->pixmap.scan_align - 1; + u32 buf_align = info->pixmap.buf_align - 1; + u32 mod = vc->vc_font.width % 8, cnt, pitch, size; + u32 attribute = get_attribute(info, scr_readw(s)); + u8 *dst, *buf = NULL; image.fg_color = fg; image.bg_color = bg; - image.dx = xx * vc->vc_font.width; image.dy = yy * vc->vc_font.height; image.height = vc->vc_font.height; image.depth = 1; + if (attribute) { + buf = kmalloc(cellsize, GFP_KERNEL); + if (!buf) + return; + } + while (count) { if (count > maxcnt) - cnt = k = maxcnt; + cnt = maxcnt; else - cnt = k = count; + cnt = count; image.width = vc->vc_font.width * cnt; pitch = ((image.width + 7) >> 3) + scan_align; @@ -147,45 +209,18 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, size &= ~buf_align; dst = fb_get_buffer_offset(info, &info->pixmap, size); image.data = dst; - if (mod) { - while (k--) { - src = vc->vc_font.data + (scr_readw(s++)& - charmask)*cellsize; - - if (attribute) { - update_attr(buf, src, attribute, vc); - src = buf; - } - - fb_pad_unaligned_buffer(dst, pitch, src, idx, - image.height, shift_high, - shift_low, mod); - shift_low += mod; - dst += (shift_low >= 8) ? width : width - 1; - shift_low &= 7; - shift_high = 8 - shift_low; - } - } else { - while (k--) { - src = vc->vc_font.data + (scr_readw(s++)& - charmask)*cellsize; - - if (attribute) { - update_attr(buf, src, attribute, vc); - src = buf; - } - - if (idx == 1) - for(i=0; i < image.height; i++) - dst[pitch*i] = src[i]; - else - fb_pad_aligned_buffer(dst, pitch, src, idx, image.height); - dst += width; - } - } - info->fbops->fb_imageblit(info, &image); + + if (!mod) + bit_putcs_aligned(vc, info, s, attribute, cnt, pitch, + width, cellsize, &image, buf, dst); + else + bit_putcs_unaligned(vc, info, s, attribute, cnt, + pitch, width, cellsize, &image, + buf, dst); + image.dx += cnt * vc->vc_font.width; count -= cnt; + s += cnt; } /* buf is always NULL except when in monochrome mode, so in this case @@ -193,6 +228,7 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, NULL pointers just fine */ if (unlikely(buf)) kfree(buf); + } static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 71b55070bdb97..70be7009f8afc 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -90,15 +90,7 @@ EXPORT_SYMBOL(fb_get_color_depth); */ void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height) { - int i, j; - - for (i = height; i--; ) { - /* s_pitch is a few bytes at the most, memcpy is suboptimal */ - for (j = 0; j < s_pitch; j++) - dst[j] = src[j]; - src += s_pitch; - dst += d_pitch; - } + __fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height); } EXPORT_SYMBOL(fb_pad_aligned_buffer); diff --git a/include/linux/fb.h b/include/linux/fb.h index 9a4f035e9fdc6..82e39cd0c4fba 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -833,6 +833,21 @@ extern int fb_new_modelist(struct fb_info *info); extern struct fb_info *registered_fb[FB_MAX]; extern int num_registered_fb; +static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, + u8 *src, u32 s_pitch, u32 height) +{ + int i, j; + + d_pitch -= s_pitch; + + for (i = height; i--; ) { + /* s_pitch is a few bytes at the most, memcpy is suboptimal */ + for (j = 0; j < s_pitch; j++) + *dst++ = *src++; + dst += d_pitch; + } +} + /* drivers/video/fbsysfs.c */ extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev); extern void framebuffer_release(struct fb_info *info); -- GitLab From 74f6ae84b2315c2fa8a4110b09a1c0f3dca92674 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:10:04 -0700 Subject: [PATCH 249/563] [PATCH] i810fb: Add i2c/DDC support Add ddc/i2c support for i810fb. This will allow the driver to get display information, especially for monitors with fickle timings. The i2c support depends on CONFIG_FB_I810_GTF. Changed __init* to __devinit* Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Alexander Nyberg <alexn@telia.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/Kconfig | 6 + drivers/video/i810/Makefile | 5 +- drivers/video/i810/i810-i2c.c | 257 +++++++++++++++++++++++++++++++++ drivers/video/i810/i810.h | 13 ++ drivers/video/i810/i810_main.c | 177 +++++++++++++++++------ drivers/video/i810/i810_main.h | 16 ++ 6 files changed, 429 insertions(+), 45 deletions(-) create mode 100644 drivers/video/i810/i810-i2c.c diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e27aefd49ea3a..f8c341d48caf7 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -751,6 +751,12 @@ config FB_I810_GTF If unsure, say N. +config FB_I810_I2C + bool "Enable DDC Support" + depends on FB_I810 && I2C && FB_I810_GTF + select I2C_ALGOBIT + help + config FB_INTEL tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)" depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64 diff --git a/drivers/video/i810/Makefile b/drivers/video/i810/Makefile index 794ae76c7c4b9..96e08c8ded979 100644 --- a/drivers/video/i810/Makefile +++ b/drivers/video/i810/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_FB_I810) += i810fb.o - i810fb-objs := i810_main.o i810_accel.o ifdef CONFIG_FB_I810_GTF @@ -12,3 +11,7 @@ i810fb-objs += i810_gtf.o else i810fb-objs += i810_dvt.o endif + +ifdef CONFIG_FB_I810_I2C +i810fb-objs += i810-i2c.o +endif diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c new file mode 100644 index 0000000000000..fda53aac1fc10 --- /dev/null +++ b/drivers/video/i810/i810-i2c.c @@ -0,0 +1,257 @@ + /*-*- linux-c -*- + * linux/drivers/video/i810-i2c.c -- Intel 810/815 I2C support + * + * Copyright (C) 2004 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/fb.h> +#include "i810.h" +#include "i810_regs.h" +#include "../edid.h" + +#define I810_DDC 0x50 +/* bit locations in the registers */ +#define SCL_DIR_MASK 0x0001 +#define SCL_DIR 0x0002 +#define SCL_VAL_MASK 0x0004 +#define SCL_VAL_OUT 0x0008 +#define SCL_VAL_IN 0x0010 +#define SDA_DIR_MASK 0x0100 +#define SDA_DIR 0x0200 +#define SDA_VAL_MASK 0x0400 +#define SDA_VAL_OUT 0x0800 +#define SDA_VAL_IN 0x1000 + +#define DEBUG /* define this for verbose EDID parsing output */ + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(fmt,## args) +#else +#define DPRINTK(fmt, args...) +#endif + +static void i810i2c_setscl(void *data, int state) +{ + struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_par *par = chan->par; + u8 *mmio = par->mmio_start_virtual; + + i810_writel(mmio, GPIOB, (state ? SCL_VAL_OUT : 0) | SCL_DIR | + SCL_DIR_MASK | SCL_VAL_MASK); + i810_readl(mmio, GPIOB); /* flush posted write */ +} + +static void i810i2c_setsda(void *data, int state) +{ + struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_par *par = chan->par; + u8 *mmio = par->mmio_start_virtual; + + i810_writel(mmio, GPIOB, (state ? SDA_VAL_OUT : 0) | SDA_DIR | + SDA_DIR_MASK | SDA_VAL_MASK); + i810_readl(mmio, GPIOB); /* flush posted write */ +} + +static int i810i2c_getscl(void *data) +{ + struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_par *par = chan->par; + u8 *mmio = par->mmio_start_virtual; + + i810_writel(mmio, GPIOB, SCL_DIR_MASK); + i810_writel(mmio, GPIOB, 0); + return (0 != (i810_readl(mmio, GPIOB) & SCL_VAL_IN)); +} + +static int i810i2c_getsda(void *data) +{ + struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_par *par = chan->par; + u8 *mmio = par->mmio_start_virtual; + + i810_writel(mmio, GPIOB, SDA_DIR_MASK); + i810_writel(mmio, GPIOB, 0); + return (0 != (i810_readl(mmio, GPIOB) & SDA_VAL_IN)); +} + +static void i810ddc_setscl(void *data, int state) +{ + struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_par *par = chan->par; + u8 *mmio = par->mmio_start_virtual; + + i810_writel(mmio, GPIOA, (state ? SCL_VAL_OUT : 0) | SCL_DIR | + SCL_DIR_MASK | SCL_VAL_MASK); + i810_readl(mmio, GPIOA); /* flush posted write */ +} + +static void i810ddc_setsda(void *data, int state) +{ + struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_par *par = chan->par; + u8 *mmio = par->mmio_start_virtual; + + i810_writel(mmio, GPIOA, (state ? SDA_VAL_OUT : 0) | SDA_DIR | + SDA_DIR_MASK | SDA_VAL_MASK); + i810_readl(mmio, GPIOA); /* flush posted write */ +} + +static int i810ddc_getscl(void *data) +{ + struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_par *par = chan->par; + u8 *mmio = par->mmio_start_virtual; + + i810_writel(mmio, GPIOA, SCL_DIR_MASK); + i810_writel(mmio, GPIOA, 0); + return (0 != (i810_readl(mmio, GPIOA) & SCL_VAL_IN)); +} + +static int i810ddc_getsda(void *data) +{ + struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_par *par = chan->par; + u8 *mmio = par->mmio_start_virtual; + + i810_writel(mmio, GPIOA, SDA_DIR_MASK); + i810_writel(mmio, GPIOA, 0); + return (0 != (i810_readl(mmio, GPIOA) & SDA_VAL_IN)); +} + +#define I2C_ALGO_DDC_I810 0x0e0000 +#define I2C_ALGO_I2C_I810 0x0f0000 +static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name, + int conn) +{ + int rc; + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->par->dev->dev; + switch (conn) { + case 1: + chan->adapter.id = I2C_ALGO_DDC_I810; + chan->algo.setsda = i810ddc_setsda; + chan->algo.setscl = i810ddc_setscl; + chan->algo.getsda = i810ddc_getsda; + chan->algo.getscl = i810ddc_getscl; + break; + case 2: + chan->adapter.id = I2C_ALGO_I2C_I810; + chan->algo.setsda = i810i2c_setsda; + chan->algo.setscl = i810i2c_setscl; + chan->algo.getsda = i810i2c_getsda; + chan->algo.getscl = i810i2c_getscl; + break; + } + chan->algo.udelay = 10; + chan->algo.mdelay = 10; + chan->algo.timeout = (HZ/2); + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + chan->algo.setsda(chan, 1); + chan->algo.setscl(chan, 1); + udelay(20); + + rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) + dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name); + else + dev_warn(&chan->par->dev->dev, "Failed to register I2C bus " + "%s.\n", name); + return rc; +} + +void i810_create_i2c_busses(struct i810fb_par *par) +{ + par->chan[0].par = par; + par->chan[1].par = par; + i810_setup_i2c_bus(&par->chan[0], "I810-DDC", 1); + i810_setup_i2c_bus(&par->chan[1], "I810-I2C", 2); +} + +void i810_delete_i2c_busses(struct i810fb_par *par) +{ + if (par->chan[0].par) + i2c_bit_del_bus(&par->chan[0].adapter); + par->chan[0].par = NULL; + if (par->chan[1].par) + i2c_bit_del_bus(&par->chan[1].adapter); + par->chan[1].par = NULL; +} + +static u8 *i810_do_probe_i2c_edid(struct i810fb_i2c_chan *chan) +{ + u8 start = 0x0; + struct i2c_msg msgs[] = { + { + .addr = I810_DDC, + .len = 1, + .buf = &start, + }, { + .addr = I810_DDC, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + }, + }; + u8 *buf; + + buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!buf) { + DPRINTK("i810-i2c: Failed to allocate memory\n"); + return NULL; + } + msgs[1].buf = buf; + + if (i2c_transfer(&chan->adapter, msgs, 2) == 2) { + DPRINTK("i810-i2c: I2C Transfer successful\n"); + return buf; + } + DPRINTK("i810-i2c: Unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + +int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn) +{ + struct i810fb_par *par = info->par; + u8 *edid = NULL; + int i; + + DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn); + if (conn < 3) { + for (i = 0; i < 3; i++) { + /* Do the real work */ + edid = i810_do_probe_i2c_edid(&par->chan[conn-1]); + if (edid) + break; + } + } else { + DPRINTK("i810-i2c: Getting EDID from BIOS\n"); + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (edid) + memcpy(edid, fb_firmware_edid(info->device), + EDID_LENGTH); + } + + if (out_edid) + *out_edid = edid; + + return (edid) ? 0 : 1; +} + + diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h index f59af3335ccf6..d48949ceaacc0 100644 --- a/drivers/video/i810/i810.h +++ b/drivers/video/i810/i810.h @@ -16,6 +16,9 @@ #include <linux/list.h> #include <linux/agp_backend.h> #include <linux/fb.h> +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> #include <video/vga.h> /* Fence */ @@ -240,6 +243,14 @@ struct state_registers { u8 cr39, cr41, cr70, sr01, msr; }; +struct i810fb_par; + +struct i810fb_i2c_chan { + struct i810fb_par *par; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; + struct i810fb_par { struct mode_registers regs; struct state_registers hw_state; @@ -251,10 +262,12 @@ struct i810fb_par { struct heap_data iring; struct heap_data cursor_heap; struct vgastate state; + struct i810fb_i2c_chan chan[2]; atomic_t use_count; u32 pseudo_palette[17]; unsigned long mmio_start_phys; u8 __iomem *mmio_start_virtual; + u8 *edid; u32 pitch; u32 pixconf; u32 watermark; diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index d07b1f203fc42..082ddd2089a5e 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -92,20 +92,21 @@ static struct pci_driver i810fb_driver = { .resume = i810fb_resume, }; -static int vram __initdata = 4; -static int bpp __initdata = 8; -static int mtrr __initdata = 0; -static int accel __initdata = 0; -static int hsync1 __initdata = 0; -static int hsync2 __initdata = 0; -static int vsync1 __initdata = 0; -static int vsync2 __initdata = 0; -static int xres __initdata = 640; -static int yres __initdata = 480; -static int vyres __initdata = 0; -static int sync __initdata = 0; -static int ext_vga __initdata = 0; -static int dcolor __initdata = 0; +static char *mode_option __devinitdata = NULL; +static int vram __devinitdata = 4; +static int bpp __devinitdata = 8; +static int mtrr __devinitdata = 0; +static int accel __devinitdata = 0; +static int hsync1 __devinitdata = 0; +static int hsync2 __devinitdata = 0; +static int vsync1 __devinitdata = 0; +static int vsync2 __devinitdata = 0; +static int xres __devinitdata = 640; +static int yres __devinitdata = 480; +static int vyres __devinitdata = 0; +static int sync __devinitdata = 0; +static int ext_vga __devinitdata = 0; +static int dcolor __devinitdata = 0; /*------------------------------------------------------------*/ @@ -947,31 +948,24 @@ static int i810_check_params(struct fb_var_screeninfo *var, struct fb_info *info) { struct i810fb_par *par = (struct i810fb_par *) info->par; - int line_length, vidmem; - u32 xres, yres, vxres, vyres; - - xres = var->xres; - yres = var->yres; - vxres = var->xres_virtual; - vyres = var->yres_virtual; - + int line_length, vidmem, mode_valid = 0; + u32 vyres = var->yres_virtual, vxres = var->xres_virtual; /* * Memory limit */ - line_length = get_line_length(par, vxres, - var->bits_per_pixel); - + line_length = get_line_length(par, vxres, var->bits_per_pixel); vidmem = line_length*vyres; + if (vidmem > par->fb.size) { vyres = par->fb.size/line_length; - if (vyres < yres) { + if (vyres < var->yres) { vyres = yres; vxres = par->fb.size/vyres; vxres /= var->bits_per_pixel >> 3; line_length = get_line_length(par, vxres, var->bits_per_pixel); vidmem = line_length * yres; - if (vxres < xres) { + if (vxres < var->xres) { printk("i810fb: required video memory, " "%d bytes, for %dx%d-%d (virtual) " "is out of range\n", @@ -981,6 +975,10 @@ static int i810_check_params(struct fb_var_screeninfo *var, } } } + + var->xres_virtual = vxres; + var->yres_virtual = vyres; + /* * Monitor limit */ @@ -996,25 +994,39 @@ static int i810_check_params(struct fb_var_screeninfo *var, info->monspecs.dclkmax = 204000000; break; } + info->monspecs.dclkmin = 15000000; - if (fb_validate_mode(var, info)) { + if (!fb_validate_mode(var, info)) + mode_valid = 1; + +#ifdef CONFIG_FB_I810_I2C + if (!mode_valid && info->monspecs.gtf && + !fb_get_mode(FB_MAXTIMINGS, 0, var, info)) + mode_valid = 1; + + if (!mode_valid && info->monspecs.modedb_len) { + struct fb_videomode *mode; + + mode = fb_find_best_mode(var, &info->modelist); + if (mode) { + fb_videomode_to_var(var, mode); + mode_valid = 1; + } + } +#endif + if (!mode_valid && info->monspecs.modedb_len == 0) { if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) { int default_sync = (info->monspecs.hfmin-HFMIN) - |(info->monspecs.hfmax-HFMAX) - |(info->monspecs.vfmin-VFMIN) - |(info->monspecs.vfmax-VFMAX); + |(info->monspecs.hfmax-HFMAX) + |(info->monspecs.vfmin-VFMIN) + |(info->monspecs.vfmax-VFMAX); printk("i810fb: invalid video mode%s\n", - default_sync ? "" : - ". Specifying vsyncN/hsyncN parameters may help"); - return -EINVAL; + default_sync ? "" : ". Specifying " + "vsyncN/hsyncN parameters may help"); } } - - var->xres = xres; - var->yres = yres; - var->xres_virtual = vxres; - var->yres_virtual = vyres; + return 0; } @@ -1812,8 +1824,72 @@ i810_allocate_pci_resource(struct i810fb_par *par, return 0; } +static void __devinit i810fb_find_init_mode(struct fb_info *info) +{ + struct fb_videomode mode; + struct fb_var_screeninfo var; + struct fb_monspecs *specs = NULL; + int found = 0; +#ifdef CONFIG_FB_I810_I2C + int i; + int err; + struct i810fb_par *par = info->par; +#endif + + INIT_LIST_HEAD(&info->modelist); + memset(&mode, 0, sizeof(struct fb_videomode)); + var = info->var; +#ifdef CONFIG_FB_I810_I2C + i810_create_i2c_busses(par); + + for (i = 0; i < 3; i++) { + err = i810_probe_i2c_connector(info, &par->edid, i+1); + if (!err) + break; + } + + if (!err) + printk("i810fb_init_pci: DDC probe successful\n"); + + fb_edid_to_monspecs(par->edid, &info->monspecs); + + if (info->monspecs.modedb == NULL) + printk("i810fb_init_pci: Unable to get Mode Database\n"); + + specs = &info->monspecs; + fb_videomode_to_modelist(specs->modedb, specs->modedb_len, + &info->modelist); + if (specs->modedb != NULL) { + if (specs->misc & FB_MISC_1ST_DETAIL) { + for (i = 0; i < specs->modedb_len; i++) { + if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { + mode = specs->modedb[i]; + found = 1; + break; + } + } + } + + if (!found) { + mode = specs->modedb[0]; + found = 1; + } + + fb_videomode_to_var(&var, &mode); + } +#endif + if (mode_option) + fb_find_mode(&var, info, mode_option, specs->modedb, + specs->modedb_len, (found) ? &mode : NULL, + info->var.bits_per_pixel); + + info->var = var; + fb_destroy_modedb(specs->modedb); + specs->modedb = NULL; +} + #ifndef MODULE -static int __init i810fb_setup(char *options) +static int __devinit i810fb_setup(char *options) { char *this_opt, *suffix = NULL; @@ -1855,6 +1931,8 @@ static int __init i810fb_setup(char *options) vsync2 = simple_strtoul(this_opt+7, NULL, 0); else if (!strncmp(this_opt, "dcolor", 6)) dcolor = 1; + else + mode_option = this_opt; } return 0; } @@ -1865,6 +1943,7 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev, { struct fb_info *info; struct i810fb_par *par = NULL; + struct fb_videomode mode; int i, err = -1, vfreq, hfreq, pixclock; i = 0; @@ -1873,7 +1952,7 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev, if (!info) return -ENOMEM; - par = (struct i810fb_par *) info->par; + par = info->par; par->dev = dev; if (!(info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL))) { @@ -1904,15 +1983,20 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev, info->fbops = &par->i810fb_ops; info->pseudo_palette = par->pseudo_palette; fb_alloc_cmap(&info->cmap, 256, 0); + i810fb_find_init_mode(info); if ((err = info->fbops->fb_check_var(&info->var, info))) { i810fb_release_resource(info, par); return err; } + + fb_var_to_videomode(&mode, &info->var); + fb_add_videomode(&mode, &info->modelist); encode_fix(&info->fix, info); i810fb_init_ringbuffer(info); err = register_framebuffer(info); + if (err < 0) { i810fb_release_resource(info, par); printk("i810fb_init: cannot register framebuffer device\n"); @@ -1951,6 +2035,8 @@ static void i810fb_release_resource(struct fb_info *info, struct gtt_data *gtt = &par->i810_gtt; unset_mtrr(par); + i810_delete_i2c_busses(par); + if (par->i810_gtt.i810_cursor_memory) agp_free_memory(gtt->i810_cursor_memory); if (par->i810_gtt.i810_fb_memory) @@ -1960,7 +2046,8 @@ static void i810fb_release_resource(struct fb_info *info, iounmap(par->mmio_start_virtual); if (par->aperture.virtual) iounmap(par->aperture.virtual); - + if (par->edid) + kfree(par->edid); if (par->res_flags & FRAMEBUFFER_REQ) release_mem_region(par->aperture.physical, par->aperture.size); @@ -1986,7 +2073,7 @@ static void __exit i810fb_remove_pci(struct pci_dev *dev) } #ifndef MODULE -static int __init i810fb_init(void) +static int __devinit i810fb_init(void) { char *option = NULL; @@ -2004,7 +2091,7 @@ static int __init i810fb_init(void) #ifdef MODULE -static int __init i810fb_init(void) +static int __devinit i810fb_init(void) { hsync1 *= 1000; hsync2 *= 1000; @@ -2052,6 +2139,8 @@ MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing" module_param(dcolor, bool, 0); MODULE_PARM_DESC(dcolor, "use DirectColor visuals" " (default = 0 = TrueColor)"); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Specify initial video mode"); MODULE_AUTHOR("Tony A. Daplas"); MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and" diff --git a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h index 43b4297b4d481..06072a6466f2c 100644 --- a/drivers/video/i810/i810_main.h +++ b/drivers/video/i810/i810_main.h @@ -83,6 +83,22 @@ extern int i810fb_sync (struct fb_info *p); extern void i810fb_init_ringbuffer(struct fb_info *info); extern void i810fb_load_front (u32 offset, struct fb_info *info); +#ifdef CONFIG_FB_I810_I2C +/* I2C */ +extern int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, + int conn); +extern void i810_create_i2c_busses(struct i810fb_par *par); +extern void i810_delete_i2c_busses(struct i810fb_par *par); +#else +static inline int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, + int conn) +{ + return 1; +} +static inline void i810_create_i2c_busses(struct i810fb_par *par) { } +static inline void i810_delete_i2c_busses(struct i810fb_par *par) { } +#endif + /* Conditionals */ #ifdef CONFIG_X86 inline void flush_cache(void) -- GitLab From 63edceac69889e48b1b39f40ca0a4c00fdc3bbb0 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Fri, 9 Sep 2005 13:10:05 -0700 Subject: [PATCH 250/563] [PATCH] i810fb: Stop LCD displays from flickering Stop LCD displays from flickering during high loads. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/i810/i810_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 082ddd2089a5e..7018ffffcbc4e 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -311,6 +311,8 @@ static void i810_hires(u8 __iomem *mmio) val = i810_readb(CR_DATA_CGA, mmio); i810_writeb(CR_INDEX_CGA, mmio, CR80); i810_writeb(CR_DATA_CGA, mmio, val | 1); + /* Stop LCD displays from flickering */ + i810_writel(MEM_MODE, mmio, i810_readl(MEM_MODE, mmio) | 4); } /** -- GitLab From 3b4abffbadf728996fb9243b4af1df48dd771e86 Mon Sep 17 00:00:00 2001 From: Olaf Hering <olh@suse.de> Date: Fri, 9 Sep 2005 13:10:06 -0700 Subject: [PATCH 251/563] [PATCH] quiet non-x86 option ROM warnings Quiet an incorrect warning in aty128fb and radeonfb about the PCI ROM content. Macs work just find without that signature. Signed-off-by: Olaf Hering <olh@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/aty/aty128fb.c | 4 ++-- drivers/video/aty/radeon_base.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index b0eba3ac6420f..e380ee8b0247d 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -806,8 +806,8 @@ static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, stru /* Very simple test to make sure it appeared */ if (BIOS_IN16(0) != 0xaa55) { - printk(KERN_ERR "aty128fb: Invalid ROM signature %x should be 0xaa55\n", - BIOS_IN16(0)); + printk(KERN_DEBUG "aty128fb: Invalid ROM signature %x should " + " be 0xaa55\n", BIOS_IN16(0)); goto failed; } diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 8a7c04c35a751..046b47860266d 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -329,8 +329,9 @@ static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev /* Very simple test to make sure it appeared */ if (BIOS_IN16(0) != 0xaa55) { - printk(KERN_ERR "radeonfb (%s): Invalid ROM signature %x should be" - "0xaa55\n", pci_name(rinfo->pdev), BIOS_IN16(0)); + printk(KERN_DEBUG "radeonfb (%s): Invalid ROM signature %x " + "should be 0xaa55\n", + pci_name(rinfo->pdev), BIOS_IN16(0)); goto failed; } /* Look for the PCI data to check the ROM type */ -- GitLab From 20fd5767689124a920c1deb9c380304e082f026c Mon Sep 17 00:00:00 2001 From: Arnaud Patard <arnaud.patard@rtp-net.org> Date: Fri, 9 Sep 2005 13:10:07 -0700 Subject: [PATCH 252/563] [PATCH] s3c2410fb: ARM S3C2410 framebuffer driver This set of two patches add support for the framebuffer of the Samsung S3C2410 ARM SoC. This driver was started about one year ago and is now used on iPAQ h1930/h1940, Acer n30 and probably other s3c2410-based machines I'm not aware of. I've also heard yesterday that it's working also on iPAQ rx3715/rx3115 (s3c2440-based machines). Signed-Off-By: Arnaud Patard <arnaud.patard@rtp-net.org> Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Ben Dooks <ben@trinity.fluff.org> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/Kconfig | 24 + drivers/video/Makefile | 1 + drivers/video/s3c2410fb.c | 915 ++++++++++++++++++++++++ drivers/video/s3c2410fb.h | 56 ++ include/asm-arm/arch-s3c2410/fb.h | 69 ++ include/asm-arm/arch-s3c2410/regs-lcd.h | 17 + 6 files changed, 1082 insertions(+) create mode 100644 drivers/video/s3c2410fb.c create mode 100644 drivers/video/s3c2410fb.h create mode 100644 include/asm-arm/arch-s3c2410/fb.h diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index f8c341d48caf7..615874e03ce8b 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1516,6 +1516,30 @@ config FB_S1D13XXX working with S1D13806). Product specs at <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm> +config FB_S3C2410 + tristate "S3C2410 LCD framebuffer support" + depends on FB && ARCH_S3C2410 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + ---help--- + Frame buffer driver for the built-in LCD controller in the Samsung + S3C2410 processor. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called s3c2410fb. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. + + If unsure, say N. +config FB_S3C2410_DEBUG + bool "S3C2410 lcd debug messages" + depends on FB_S3C2410 + help + Turn on debugging messages. Note that you can set/unset at run time + through sysfs + config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" depends on FB diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 4e7d8d27b9136..1fff29f48ca89 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -94,6 +94,7 @@ obj-$(CONFIG_FB_MAXINE) += maxinefb.o obj-$(CONFIG_FB_TX3912) += tx3912fb.o obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_IMX) += imxfb.o +obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_VESA) += vesafb.o diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c new file mode 100644 index 0000000000000..00c0223a352ea --- /dev/null +++ b/drivers/video/s3c2410fb.c @@ -0,0 +1,915 @@ +/* + * linux/drivers/video/s3c2410fb.c + * Copyright (c) Arnaud Patard, Ben Dooks + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * S3C2410 LCD Controller Frame Buffer Driver + * based on skeletonfb.c, sa1100fb.c and others + * + * ChangeLog + * 2005-04-07: Arnaud Patard <arnaud.patard@rtp-net.org> + * - u32 state -> pm_message_t state + * - S3C2410_{VA,SZ}_LCD -> S3C24XX + * + * 2005-03-15: Arnaud Patard <arnaud.patard@rtp-net.org> + * - Removed the ioctl + * - use readl/writel instead of __raw_writel/__raw_readl + * + * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org> + * - Added the possibility to set on or off the + * debugging mesaages + * - Replaced 0 and 1 by on or off when reading the + * /sys files + * + * 2005-03-23: Ben Dooks <ben-linux@fluff.org> + * - added non 16bpp modes + * - updated platform information for range of x/y/bpp + * - add code to ensure palette is written correctly + * - add pixel clock divisor control + * + * 2004-11-11: Arnaud Patard <arnaud.patard@rtp-net.org> + * - Removed the use of currcon as it no more exist + * - Added LCD power sysfs interface + * + * 2004-11-03: Ben Dooks <ben-linux@fluff.org> + * - minor cleanups + * - add suspend/resume support + * - s3c2410fb_setcolreg() not valid in >8bpp modes + * - removed last CONFIG_FB_S3C2410_FIXED + * - ensure lcd controller stopped before cleanup + * - added sysfs interface for backlight power + * - added mask for gpio configuration + * - ensured IRQs disabled during GPIO configuration + * - disable TPAL before enabling video + * + * 2004-09-20: Arnaud Patard <arnaud.patard@rtp-net.org> + * - Suppress command line options + * + * 2004-09-15: Arnaud Patard <arnaud.patard@rtp-net.org> + * - code cleanup + * + * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org> + * - Renamed from h1940fb.c to s3c2410fb.c + * - Add support for different devices + * - Backlight support + * + * 2004-09-05: Herbert P�tzl <herbert@13thfloor.at> + * - added clock (de-)allocation code + * - added fixem fbmem option + * + * 2004-07-27: Arnaud Patard <arnaud.patard@rtp-net.org> + * - code cleanup + * - added a forgotten return in h1940fb_init + * + * 2004-07-19: Herbert P�tzl <herbert@13thfloor.at> + * - code cleanup and extended debugging + * + * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org> + * - First version + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/string.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/wait.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/div64.h> + +#include <asm/mach/map.h> +#include <asm/arch/regs-lcd.h> +#include <asm/arch/regs-gpio.h> +#include <asm/arch/fb.h> +#include <asm/hardware/clock.h> + +#ifdef CONFIG_PM +#include <linux/pm.h> +#endif + +#include "s3c2410fb.h" + + +static struct s3c2410fb_mach_info *mach_info; + +/* Debugging stuff */ +#ifdef CONFIG_FB_S3C2410_DEBUG +static int debug = 1; +#else +static int debug = 0; +#endif + +#define dprintk(msg...) if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); } + +/* useful functions */ + +/* s3c2410fb_set_lcdaddr + * + * initialise lcd controller address pointers +*/ + +static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi) +{ + struct fb_var_screeninfo *var = &fbi->fb->var; + unsigned long saddr1, saddr2, saddr3; + + saddr1 = fbi->fb->fix.smem_start >> 1; + saddr2 = fbi->fb->fix.smem_start; + saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8; + saddr2>>= 1; + + saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(var->xres); + + dprintk("LCDSADDR1 = 0x%08lx\n", saddr1); + dprintk("LCDSADDR2 = 0x%08lx\n", saddr2); + dprintk("LCDSADDR3 = 0x%08lx\n", saddr3); + + writel(saddr1, S3C2410_LCDSADDR1); + writel(saddr2, S3C2410_LCDSADDR2); + writel(saddr3, S3C2410_LCDSADDR3); +} + +/* s3c2410fb_calc_pixclk() + * + * calculate divisor for clk->pixclk +*/ + +static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, + unsigned long pixclk) +{ + unsigned long clk = clk_get_rate(fbi->clk); + unsigned long long div; + + /* pixclk is in picoseoncds, our clock is in Hz + * + * Hz -> picoseconds is / 10^-12 + */ + + div = (unsigned long long)clk * pixclk; + do_div(div,1000000UL); + do_div(div,1000000UL); + + dprintk("pixclk %ld, divisor is %ld\n", pixclk, (long)div); + return div; +} + +/* + * s3c2410fb_check_var(): + * Get the video params out of 'var'. If a value doesn't fit, round it up, + * if it's too big, return -EINVAL. + * + */ +static int s3c2410fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct s3c2410fb_info *fbi = info->par; + + dprintk("check_var(var=%p, info=%p)\n", var, info); + + /* validate x/y resolution */ + + if (var->yres > fbi->mach_info->yres.max) + var->yres = fbi->mach_info->yres.max; + else if (var->yres < fbi->mach_info->yres.min) + var->yres = fbi->mach_info->yres.min; + + if (var->xres > fbi->mach_info->xres.max) + var->yres = fbi->mach_info->xres.max; + else if (var->xres < fbi->mach_info->xres.min) + var->xres = fbi->mach_info->xres.min; + + /* validate bpp */ + + if (var->bits_per_pixel > fbi->mach_info->bpp.max) + var->bits_per_pixel = fbi->mach_info->bpp.max; + else if (var->bits_per_pixel < fbi->mach_info->bpp.min) + var->bits_per_pixel = fbi->mach_info->bpp.min; + + /* set r/g/b positions */ + + if (var->bits_per_pixel == 16) { + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.length = 0; + } else { + var->red.length = var->bits_per_pixel; + var->red.offset = 0; + var->green.length = var->bits_per_pixel; + var->green.offset = 0; + var->blue.length = var->bits_per_pixel; + var->blue.offset = 0; + var->transp.length = 0; + } + + return 0; +} + +/* s3c2410fb_activate_var + * + * activate (set) the controller from the given framebuffer + * information +*/ + +static int s3c2410fb_activate_var(struct s3c2410fb_info *fbi, + struct fb_var_screeninfo *var) +{ + fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK; + + dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); + dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); + dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); + + switch (var->bits_per_pixel) { + case 1: + fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP; + break; + case 2: + fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP; + break; + case 4: + fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP; + break; + case 8: + fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP; + break; + case 16: + fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP; + break; + } + + /* check to see if we need to update sync/borders */ + + if (!fbi->mach_info->fixed_syncs) { + dprintk("setting vert: up=%d, low=%d, sync=%d\n", + var->upper_margin, var->lower_margin, + var->vsync_len); + + dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", + var->left_margin, var->right_margin, + var->hsync_len); + + fbi->regs.lcdcon2 = + S3C2410_LCDCON2_VBPD(var->upper_margin - 1) | + S3C2410_LCDCON2_VFPD(var->lower_margin - 1) | + S3C2410_LCDCON2_VSPW(var->vsync_len - 1); + + fbi->regs.lcdcon3 = + S3C2410_LCDCON3_HBPD(var->right_margin - 1) | + S3C2410_LCDCON3_HFPD(var->left_margin - 1); + + fbi->regs.lcdcon4 &= ~S3C2410_LCDCON4_HSPW(0xff); + fbi->regs.lcdcon4 |= S3C2410_LCDCON4_HSPW(var->hsync_len - 1); + } + + /* update X/Y info */ + + fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff); + fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1); + + fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff); + fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(var->xres - 1); + + if (var->pixclock > 0) { + int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock); + + clkdiv = (clkdiv / 2) -1; + if (clkdiv < 0) + clkdiv = 0; + + fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff); + fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv); + } + + /* write new registers */ + + dprintk("new register set:\n"); + dprintk("lcdcon[1] = 0x%08lx\n", fbi->regs.lcdcon1); + dprintk("lcdcon[2] = 0x%08lx\n", fbi->regs.lcdcon2); + dprintk("lcdcon[3] = 0x%08lx\n", fbi->regs.lcdcon3); + dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4); + dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5); + + writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); + writel(fbi->regs.lcdcon2, S3C2410_LCDCON2); + writel(fbi->regs.lcdcon3, S3C2410_LCDCON3); + writel(fbi->regs.lcdcon4, S3C2410_LCDCON4); + writel(fbi->regs.lcdcon5, S3C2410_LCDCON5); + + /* set lcd address pointers */ + s3c2410fb_set_lcdaddr(fbi); + + writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); +} + + +/* + * s3c2410fb_set_par - Optional function. Alters the hardware state. + * @info: frame buffer structure that represents a single frame buffer + * + */ +static int s3c2410fb_set_par(struct fb_info *info) +{ + struct s3c2410fb_info *fbi = info->par; + struct fb_var_screeninfo *var = &info->var; + + if (var->bits_per_pixel == 16) + fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR; + else + fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + + fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8; + + /* activate this new configuration */ + + s3c2410fb_activate_var(fbi, var); + return 0; +} + +static void schedule_palette_update(struct s3c2410fb_info *fbi, + unsigned int regno, unsigned int val) +{ + unsigned long flags; + unsigned long irqen; + + local_irq_save(flags); + + fbi->palette_buffer[regno] = val; + + if (!fbi->palette_ready) { + fbi->palette_ready = 1; + + /* enable IRQ */ + irqen = readl(S3C2410_LCDINTMSK); + irqen &= ~S3C2410_LCDINT_FRSYNC; + writel(irqen, S3C2410_LCDINTMSK); + } + + local_irq_restore(flags); +} + +/* from pxafb.c */ +static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int s3c2410fb_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct s3c2410fb_info *fbi = info->par; + unsigned int val; + + /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n", regno, red, green, blue); */ + + switch (fbi->fb->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* true-colour, use pseuo-palette */ + + if (regno < 16) { + u32 *pal = fbi->fb->pseudo_palette; + + val = chan_to_field(red, &fbi->fb->var.red); + val |= chan_to_field(green, &fbi->fb->var.green); + val |= chan_to_field(blue, &fbi->fb->var.blue); + + pal[regno] = val; + } + break; + + case FB_VISUAL_PSEUDOCOLOR: + if (regno < 256) { + /* currently assume RGB 5-6-5 mode */ + + val = ((red >> 0) & 0xf800); + val |= ((green >> 5) & 0x07e0); + val |= ((blue >> 11) & 0x001f); + + writel(val, S3C2410_TFTPAL(regno)); + schedule_palette_update(fbi, regno, val); + } + + break; + + default: + return 1; /* unknown type */ + } + + return 0; +} + + +/** + * s3c2410fb_blank + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + * + * Blank the screen if blank_mode != 0, else unblank. Return 0 if + * blanking succeeded, != 0 if un-/blanking failed due to e.g. a + * video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + * + * Returns negative errno on error, or zero on success. + * + */ +static int s3c2410fb_blank(int blank_mode, struct fb_info *info) +{ + dprintk("blank(mode=%d, info=%p)\n", blank_mode, info); + + if (mach_info == NULL) + return -EINVAL; + + if (blank_mode == FB_BLANK_UNBLANK) + writel(0x0, S3C2410_TPAL); + else { + dprintk("setting TPAL to output 0x000000\n"); + writel(S3C2410_TPAL_EN, S3C2410_TPAL); + } + + return 0; +} + +static int s3c2410fb_debug_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", debug ? "on" : "off"); +} +static int s3c2410fb_debug_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + if (mach_info == NULL) + return -EINVAL; + + if (len < 1) + return -EINVAL; + + if (strnicmp(buf, "on", 2) == 0 || + strnicmp(buf, "1", 1) == 0) { + debug = 1; + printk(KERN_DEBUG "s3c2410fb: Debug On"); + } else if (strnicmp(buf, "off", 3) == 0 || + strnicmp(buf, "0", 1) == 0) { + debug = 0; + printk(KERN_DEBUG "s3c2410fb: Debug Off"); + } else { + return -EINVAL; + } + + return len; +} + + +static DEVICE_ATTR(debug, 0666, + s3c2410fb_debug_show, + s3c2410fb_debug_store); + +static struct fb_ops s3c2410fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = s3c2410fb_check_var, + .fb_set_par = s3c2410fb_set_par, + .fb_blank = s3c2410fb_blank, + .fb_setcolreg = s3c2410fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, +}; + + +/* + * s3c2410fb_map_video_memory(): + * Allocates the DRAM memory for the frame buffer. This buffer is + * remapped into a non-cached, non-buffered, memory region to + * allow palette and pixel writes to occur without flushing the + * cache. Once this area is remapped, all virtual memory + * access to the video memory should occur at the new region. + */ +static int __init s3c2410fb_map_video_memory(struct s3c2410fb_info *fbi) +{ + dprintk("map_video_memory(fbi=%p)\n", fbi); + + fbi->map_size = PAGE_ALIGN(fbi->fb->fix.smem_len + PAGE_SIZE); + fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, + &fbi->map_dma, GFP_KERNEL); + + fbi->map_size = fbi->fb->fix.smem_len; + + if (fbi->map_cpu) { + /* prevent initial garbage on screen */ + dprintk("map_video_memory: clear %p:%08x\n", + fbi->map_cpu, fbi->map_size); + memset(fbi->map_cpu, 0xf0, fbi->map_size); + + fbi->screen_dma = fbi->map_dma; + fbi->fb->screen_base = fbi->map_cpu; + fbi->fb->fix.smem_start = fbi->screen_dma; + + dprintk("map_video_memory: dma=%08x cpu=%p size=%08x\n", + fbi->map_dma, fbi->map_cpu, fbi->fb->fix.smem_len); + } + + return fbi->map_cpu ? 0 : -ENOMEM; +} + +static inline void s3c2410fb_unmap_video_memory(struct s3c2410fb_info *fbi) +{ + dma_free_writecombine(fbi->dev,fbi->map_size,fbi->map_cpu, fbi->map_dma); +} + +static inline void modify_gpio(void __iomem *reg, + unsigned long set, unsigned long mask) +{ + unsigned long tmp; + + tmp = readl(reg) & ~mask; + writel(tmp | set, reg); +} + + +/* + * s3c2410fb_init_registers - Initialise all LCD-related registers + */ + +int s3c2410fb_init_registers(struct s3c2410fb_info *fbi) +{ + unsigned long flags; + + /* Initialise LCD with values from haret */ + + local_irq_save(flags); + + /* modify the gpio(s) with interrupts set (bjd) */ + + modify_gpio(S3C2410_GPCUP, mach_info->gpcup, mach_info->gpcup_mask); + modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask); + modify_gpio(S3C2410_GPDUP, mach_info->gpdup, mach_info->gpdup_mask); + modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask); + + local_irq_restore(flags); + + writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); + writel(fbi->regs.lcdcon2, S3C2410_LCDCON2); + writel(fbi->regs.lcdcon3, S3C2410_LCDCON3); + writel(fbi->regs.lcdcon4, S3C2410_LCDCON4); + writel(fbi->regs.lcdcon5, S3C2410_LCDCON5); + + s3c2410fb_set_lcdaddr(fbi); + + dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel); + writel(mach_info->lpcsel, S3C2410_LPCSEL); + + dprintk("replacing TPAL %08x\n", readl(S3C2410_TPAL)); + + /* ensure temporary palette disabled */ + writel(0x00, S3C2410_TPAL); + + /* Enable video by setting the ENVID bit to 1 */ + fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID; + writel(fbi->regs.lcdcon1, S3C2410_LCDCON1); + return 0; +} + +static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi) +{ + unsigned int i; + unsigned long ent; + + fbi->palette_ready = 0; + + for (i = 0; i < 256; i++) { + if ((ent = fbi->palette_buffer[i]) == PALETTE_BUFF_CLEAR) + continue; + + writel(ent, S3C2410_TFTPAL(i)); + + /* it seems the only way to know exactly + * if the palette wrote ok, is to check + * to see if the value verifies ok + */ + + if (readw(S3C2410_TFTPAL(i)) == ent) + fbi->palette_buffer[i] = PALETTE_BUFF_CLEAR; + else + fbi->palette_ready = 1; /* retry */ + } +} + +static irqreturn_t s3c2410fb_irq(int irq, void *dev_id, struct pt_regs *r) +{ + struct s3c2410fb_info *fbi = dev_id; + unsigned long lcdirq = readl(S3C2410_LCDINTPND); + + if (lcdirq & S3C2410_LCDINT_FRSYNC) { + if (fbi->palette_ready) + s3c2410fb_write_palette(fbi); + + writel(S3C2410_LCDINT_FRSYNC, S3C2410_LCDINTPND); + writel(S3C2410_LCDINT_FRSYNC, S3C2410_LCDSRCPND); + } + + return IRQ_HANDLED; +} + +static char driver_name[]="s3c2410fb"; + +int __init s3c2410fb_probe(struct device *dev) +{ + struct s3c2410fb_info *info; + struct fb_info *fbinfo; + struct platform_device *pdev = to_platform_device(dev); + struct s3c2410fb_hw *mregs; + int ret; + int irq; + int i; + + mach_info = dev->platform_data; + if (mach_info == NULL) { + dev_err(dev,"no platform data for lcd, cannot attach\n"); + return -EINVAL; + } + + mregs = &mach_info->regs; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no irq for device\n"); + return -ENOENT; + } + + fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), dev); + if (!fbinfo) { + return -ENOMEM; + } + + + info = fbinfo->par; + info->fb = fbinfo; + dev_set_drvdata(dev, fbinfo); + + s3c2410fb_init_registers(info); + + dprintk("devinit\n"); + + strcpy(fbinfo->fix.id, driver_name); + + memcpy(&info->regs, &mach_info->regs, sizeof(info->regs)); + + info->mach_info = dev->platform_data; + + fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; + fbinfo->fix.type_aux = 0; + fbinfo->fix.xpanstep = 0; + fbinfo->fix.ypanstep = 0; + fbinfo->fix.ywrapstep = 0; + fbinfo->fix.accel = FB_ACCEL_NONE; + + fbinfo->var.nonstd = 0; + fbinfo->var.activate = FB_ACTIVATE_NOW; + fbinfo->var.height = mach_info->height; + fbinfo->var.width = mach_info->width; + fbinfo->var.accel_flags = 0; + fbinfo->var.vmode = FB_VMODE_NONINTERLACED; + + fbinfo->fbops = &s3c2410fb_ops; + fbinfo->flags = FBINFO_FLAG_DEFAULT; + fbinfo->pseudo_palette = &info->pseudo_pal; + + fbinfo->var.xres = mach_info->xres.defval; + fbinfo->var.xres_virtual = mach_info->xres.defval; + fbinfo->var.yres = mach_info->yres.defval; + fbinfo->var.yres_virtual = mach_info->yres.defval; + fbinfo->var.bits_per_pixel = mach_info->bpp.defval; + + fbinfo->var.upper_margin = S3C2410_LCDCON2_GET_VBPD(mregs->lcdcon2) +1; + fbinfo->var.lower_margin = S3C2410_LCDCON2_GET_VFPD(mregs->lcdcon2) +1; + fbinfo->var.vsync_len = S3C2410_LCDCON2_GET_VSPW(mregs->lcdcon2) + 1; + + fbinfo->var.left_margin = S3C2410_LCDCON3_GET_HFPD(mregs->lcdcon3) + 1; + fbinfo->var.right_margin = S3C2410_LCDCON3_GET_HBPD(mregs->lcdcon3) + 1; + fbinfo->var.hsync_len = S3C2410_LCDCON4_GET_HSPW(mregs->lcdcon4) + 1; + + fbinfo->var.red.offset = 11; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 0; + fbinfo->var.transp.offset = 0; + fbinfo->var.red.length = 5; + fbinfo->var.green.length = 6; + fbinfo->var.blue.length = 5; + fbinfo->var.transp.length = 0; + fbinfo->fix.smem_len = mach_info->xres.max * + mach_info->yres.max * + mach_info->bpp.max / 8; + + for (i = 0; i < 256; i++) + info->palette_buffer[i] = PALETTE_BUFF_CLEAR; + + if (!request_mem_region((unsigned long)S3C24XX_VA_LCD, SZ_1M, "s3c2410-lcd")) { + ret = -EBUSY; + goto dealloc_fb; + } + + + dprintk("got LCD region\n"); + + ret = request_irq(irq, s3c2410fb_irq, SA_INTERRUPT, pdev->name, info); + if (ret) { + dev_err(dev, "cannot get irq %d - err %d\n", irq, ret); + ret = -EBUSY; + goto release_mem; + } + + info->clk = clk_get(NULL, "lcd"); + if (!info->clk || IS_ERR(info->clk)) { + printk(KERN_ERR "failed to get lcd clock source\n"); + ret = -ENOENT; + goto release_irq; + } + + clk_use(info->clk); + clk_enable(info->clk); + dprintk("got and enabled clock\n"); + + msleep(1); + + /* Initialize video memory */ + ret = s3c2410fb_map_video_memory(info); + if (ret) { + printk( KERN_ERR "Failed to allocate video RAM: %d\n", ret); + ret = -ENOMEM; + goto release_clock; + } + dprintk("got video memory\n"); + + ret = s3c2410fb_init_registers(info); + + ret = s3c2410fb_check_var(&fbinfo->var, fbinfo); + + ret = register_framebuffer(fbinfo); + if (ret < 0) { + printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret); + goto free_video_memory; + } + + /* create device files */ + device_create_file(dev, &dev_attr_debug); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + fbinfo->node, fbinfo->fix.id); + + return 0; + +free_video_memory: + s3c2410fb_unmap_video_memory(info); +release_clock: + clk_disable(info->clk); + clk_unuse(info->clk); + clk_put(info->clk); +release_irq: + free_irq(irq,info); +release_mem: + release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD); +dealloc_fb: + framebuffer_release(fbinfo); + return ret; +} + +/* s3c2410fb_stop_lcd + * + * shutdown the lcd controller +*/ + +static void s3c2410fb_stop_lcd(void) +{ + unsigned long flags; + unsigned long tmp; + + local_irq_save(flags); + + tmp = readl(S3C2410_LCDCON1); + writel(tmp & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); + + local_irq_restore(flags); +} + +/* + * Cleanup + */ +static int s3c2410fb_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fb_info *fbinfo = dev_get_drvdata(dev); + struct s3c2410fb_info *info = fbinfo->par; + int irq; + + s3c2410fb_stop_lcd(); + msleep(1); + + s3c2410fb_unmap_video_memory(info); + + if (info->clk) { + clk_disable(info->clk); + clk_unuse(info->clk); + clk_put(info->clk); + info->clk = NULL; + } + + irq = platform_get_irq(pdev, 0); + free_irq(irq,info); + release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD); + unregister_framebuffer(fbinfo); + + return 0; +} + +#ifdef CONFIG_PM + +/* suspend and resume support for the lcd controller */ + +static int s3c2410fb_suspend(struct device *dev, pm_message_t state, u32 level) +{ + struct fb_info *fbinfo = dev_get_drvdata(dev); + struct s3c2410fb_info *info = fbinfo->par; + + if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) { + s3c2410fb_stop_lcd(); + + /* sleep before disabling the clock, we need to ensure + * the LCD DMA engine is not going to get back on the bus + * before the clock goes off again (bjd) */ + + msleep(1); + clk_disable(info->clk); + } + + return 0; +} + +static int s3c2410fb_resume(struct device *dev, u32 level) +{ + struct fb_info *fbinfo = dev_get_drvdata(dev); + struct s3c2410fb_info *info = fbinfo->par; + + if (level == RESUME_ENABLE) { + clk_enable(info->clk); + msleep(1); + + s3c2410fb_init_registers(info); + + } + + return 0; +} + +#else +#define s3c2410fb_suspend NULL +#define s3c2410fb_resume NULL +#endif + +static struct device_driver s3c2410fb_driver = { + .name = "s3c2410-lcd", + .bus = &platform_bus_type, + .probe = s3c2410fb_probe, + .suspend = s3c2410fb_suspend, + .resume = s3c2410fb_resume, + .remove = s3c2410fb_remove +}; + +int __devinit s3c2410fb_init(void) +{ + return driver_register(&s3c2410fb_driver); +} + +static void __exit s3c2410fb_cleanup(void) +{ + driver_unregister(&s3c2410fb_driver); +} + + +module_init(s3c2410fb_init); +module_exit(s3c2410fb_cleanup); + +MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, Ben Dooks <ben-linux@fluff.org>"); +MODULE_DESCRIPTION("Framebuffer driver for the s3c2410"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h new file mode 100644 index 0000000000000..be40968f899e4 --- /dev/null +++ b/drivers/video/s3c2410fb.h @@ -0,0 +1,56 @@ +/* + * linux/drivers/s3c2410fb.h + * Copyright (c) Arnaud Patard + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * S3C2410 LCD Controller Frame Buffer Driver + * based on skeletonfb.c, sa1100fb.h + * + * ChangeLog + * + * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org> + * - Moved dprintk to s3c2410fb.c + * + * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org> + * - Renamed from h1940fb.h to s3c2410fb.h + * - Chenged h1940 to s3c2410 + * + * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org> + * - First version + */ + +#ifndef __S3C2410FB_H +#define __S3C2410FB_H + +struct s3c2410fb_info { + struct fb_info *fb; + struct device *dev; + struct clk *clk; + + struct s3c2410fb_mach_info *mach_info; + + /* raw memory addresses */ + dma_addr_t map_dma; /* physical */ + u_char * map_cpu; /* virtual */ + u_int map_size; + + struct s3c2410fb_hw regs; + + /* addresses of pieces placed in raw buffer */ + u_char * screen_cpu; /* virtual address of buffer */ + dma_addr_t screen_dma; /* physical address of buffer */ + unsigned int palette_ready; + + /* keep these registers in case we need to re-write palette */ + u32 palette_buffer[256]; + u32 pseudo_pal[16]; +}; + +#define PALETTE_BUFF_CLEAR (0x80000000) /* entry is clear/invalid */ + +int s3c2410fb_init(void); + +#endif diff --git a/include/asm-arm/arch-s3c2410/fb.h b/include/asm-arm/arch-s3c2410/fb.h new file mode 100644 index 0000000000000..ac57bc887d82f --- /dev/null +++ b/include/asm-arm/arch-s3c2410/fb.h @@ -0,0 +1,69 @@ +/* linux/include/asm/arch-s3c2410/fb.h + * + * Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org> + * + * Inspired by pxafb.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * + * Changelog: + * 07-Sep-2004 RTP Created file + * 03-Nov-2004 BJD Updated and minor cleanups + * 03-Aug-2005 RTP Renamed to fb.h +*/ + +#ifndef __ASM_ARM_FB_H +#define __ASM_ARM_FB_H + +#include <asm/arch/regs-lcd.h> + +struct s3c2410fb_val { + unsigned int defval; + unsigned int min; + unsigned int max; +}; + +struct s3c2410fb_hw { + unsigned long lcdcon1; + unsigned long lcdcon2; + unsigned long lcdcon3; + unsigned long lcdcon4; + unsigned long lcdcon5; +}; + +struct s3c2410fb_mach_info { + unsigned char fixed_syncs; /* do not update sync/border */ + + /* Screen size */ + int width; + int height; + + /* Screen info */ + struct s3c2410fb_val xres; + struct s3c2410fb_val yres; + struct s3c2410fb_val bpp; + + /* lcd configuration registers */ + struct s3c2410fb_hw regs; + + /* GPIOs */ + + unsigned long gpcup; + unsigned long gpcup_mask; + unsigned long gpccon; + unsigned long gpccon_mask; + unsigned long gpdup; + unsigned long gpdup_mask; + unsigned long gpdcon; + unsigned long gpdcon_mask; + + /* lpc3600 control register */ + unsigned long lpcsel; +}; + +void __init set_s3c2410fb_info(struct s3c2410fb_mach_info *hard_s3c2410fb_info); + +#endif /* __ASM_ARM_FB_H */ diff --git a/include/asm-arm/arch-s3c2410/regs-lcd.h b/include/asm-arm/arch-s3c2410/regs-lcd.h index 7f882ea92b2a7..b6b1b4e8bbebf 100644 --- a/include/asm-arm/arch-s3c2410/regs-lcd.h +++ b/include/asm-arm/arch-s3c2410/regs-lcd.h @@ -51,21 +51,32 @@ #define S3C2410_LCDCON1_ENVID (1) +#define S3C2410_LCDCON1_MODEMASK 0x1E + #define S3C2410_LCDCON2_VBPD(x) ((x) << 24) #define S3C2410_LCDCON2_LINEVAL(x) ((x) << 14) #define S3C2410_LCDCON2_VFPD(x) ((x) << 6) #define S3C2410_LCDCON2_VSPW(x) ((x) << 0) +#define S3C2410_LCDCON2_GET_VBPD(x) ( ((x) >> 24) & 0xFF) +#define S3C2410_LCDCON2_GET_VFPD(x) ( ((x) >> 6) & 0xFF) +#define S3C2410_LCDCON2_GET_VSPW(x) ( ((x) >> 0) & 0x3F) + #define S3C2410_LCDCON3_HBPD(x) ((x) << 19) #define S3C2410_LCDCON3_WDLY(x) ((x) << 19) #define S3C2410_LCDCON3_HOZVAL(x) ((x) << 8) #define S3C2410_LCDCON3_HFPD(x) ((x) << 0) #define S3C2410_LCDCON3_LINEBLANK(x)((x) << 0) +#define S3C2410_LCDCON3_GET_HBPD(x) ( ((x) >> 19) & 0x7F) +#define S3C2410_LCDCON3_GET_HFPD(x) ( ((x) >> 0) & 0xFF) + #define S3C2410_LCDCON4_MVAL(x) ((x) << 8) #define S3C2410_LCDCON4_HSPW(x) ((x) << 0) #define S3C2410_LCDCON4_WLH(x) ((x) << 0) +#define S3C2410_LCDCON4_GET_HSPW(x) ( ((x) >> 0) & 0xFF) + #define S3C2410_LCDCON5_BPP24BL (1<<12) #define S3C2410_LCDCON5_FRM565 (1<<11) #define S3C2410_LCDCON5_INVVCLK (1<<10) @@ -100,10 +111,16 @@ #define S3C2410_DITHMODE S3C2410_LCDREG(0x4C) #define S3C2410_TPAL S3C2410_LCDREG(0x50) +#define S3C2410_TPAL_EN (1<<24) + /* interrupt info */ #define S3C2410_LCDINTPND S3C2410_LCDREG(0x54) #define S3C2410_LCDSRCPND S3C2410_LCDREG(0x58) #define S3C2410_LCDINTMSK S3C2410_LCDREG(0x5C) +#define S3C2410_LCDINT_FIWSEL (1<<2) +#define S3C2410_LCDINT_FRSYNC (1<<1) +#define S3C2410_LCDINT_FICNT (1<<0) + #define S3C2410_LPCSEL S3C2410_LCDREG(0x60) #define S3C2410_TFTPAL(x) S3C2410_LCDREG((0x400 + (x)*4)) -- GitLab From f92273c1653feadc8231c0bc4fa37fd4dc1c180f Mon Sep 17 00:00:00 2001 From: Arnaud Patard <arnaud.patard@rtp-net.org> Date: Fri, 9 Sep 2005 13:10:10 -0700 Subject: [PATCH 253/563] [PATCH] s3c2410fb: Platform support for ARM S3C2410 framebuffer driver This patch add the plateform specific stuff needed to configure and use the driver. Signed-Off-By: Arnaud Patard <arnaud.patard@rtp-net.org> Signed-off-by: Antonino Daplas <adaplas@pol.net> Cc: Russell King <rmk@arm.linux.org.uk> Cc: Ben Dooks <ben@trinity.fluff.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/arm/mach-s3c2410/devs.c | 11 ++++++- arch/arm/mach-s3c2410/mach-h1940.c | 51 ++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c index 4664bd11adc1e..0077937a7ab86 100644 --- a/arch/arm/mach-s3c2410/devs.c +++ b/arch/arm/mach-s3c2410/devs.c @@ -29,7 +29,7 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/irq.h> - +#include <asm/arch/fb.h> #include <asm/hardware.h> #include <asm/io.h> #include <asm/irq.h> @@ -103,6 +103,15 @@ struct platform_device s3c_device_lcd = { EXPORT_SYMBOL(s3c_device_lcd); +static struct s3c2410fb_mach_info s3c2410fb_info; + +void __init set_s3c2410fb_info(struct s3c2410fb_mach_info *hard_s3c2410fb_info) +{ + memcpy(&s3c2410fb_info,hard_s3c2410fb_info,sizeof(struct s3c2410fb_mach_info)); + s3c_device_lcd.dev.platform_data = &s3c2410fb_info; +} +EXPORT_SYMBOL(set_s3c2410fb_info); + /* NAND Controller */ static struct resource s3c_nand_resource[] = { diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c index ea4fb1a97a50a..6ff1889fbd21f 100644 --- a/arch/arm/mach-s3c2410/mach-h1940.c +++ b/arch/arm/mach-s3c2410/mach-h1940.c @@ -45,6 +45,9 @@ //#include <asm/debug-ll.h> #include <asm/arch/regs-serial.h> +#include <asm/arch/regs-lcd.h> + +#include <asm/arch/fb.h> #include <linux/serial_core.h> @@ -88,6 +91,48 @@ static struct s3c2410_uartcfg h1940_uartcfgs[] = { +/** + * Set lcd on or off + **/ +static struct s3c2410fb_mach_info h1940_lcdcfg __initdata = { + .fixed_syncs= 1, + .regs={ + .lcdcon1= S3C2410_LCDCON1_TFT16BPP | \ + S3C2410_LCDCON1_TFT | \ + S3C2410_LCDCON1_CLKVAL(0x0C), + + .lcdcon2= S3C2410_LCDCON2_VBPD(7) | \ + S3C2410_LCDCON2_LINEVAL(319) | \ + S3C2410_LCDCON2_VFPD(6) | \ + S3C2410_LCDCON2_VSPW(0), + + .lcdcon3= S3C2410_LCDCON3_HBPD(19) | \ + S3C2410_LCDCON3_HOZVAL(239) | \ + S3C2410_LCDCON3_HFPD(7), + + .lcdcon4= S3C2410_LCDCON4_MVAL(0) | \ + S3C2410_LCDCON4_HSPW(3), + + .lcdcon5= S3C2410_LCDCON5_FRM565 | \ + S3C2410_LCDCON5_INVVLINE | \ + S3C2410_LCDCON5_HWSWP, + }, + .lpcsel= 0x02, + .gpccon= 0xaa940659, + .gpccon_mask= 0xffffffff, + .gpcup= 0x0000ffff, + .gpcup_mask= 0xffffffff, + .gpdcon= 0xaa84aaa0, + .gpdcon_mask= 0xffffffff, + .gpdup= 0x0000faff, + .gpdup_mask= 0xffffffff, + + .width= 240, + .height= 320, + .xres= {240,240,240}, + .yres= {320,320,320}, + .bpp= {16,16,16}, +}; static struct platform_device *h1940_devices[] __initdata = { &s3c_device_usb, @@ -116,6 +161,11 @@ void __init h1940_init_irq(void) } +void __init h1940_init(void) +{ + set_s3c2410fb_info(&h1940_lcdcfg); +} + MACHINE_START(H1940, "IPAQ-H1940") /* Maintainer: Ben Dooks <ben@fluff.org> */ .phys_ram = S3C2410_SDRAM_PA, @@ -124,5 +174,6 @@ MACHINE_START(H1940, "IPAQ-H1940") .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = h1940_map_io, .init_irq = h1940_init_irq, + .init_machine = h1940_init, .timer = &s3c24xx_timer, MACHINE_END -- GitLab From b6c17ea4eff360359d1741272028610035bb2da9 Mon Sep 17 00:00:00 2001 From: Rusty Russell <rusty@rustcorp.com.au> Date: Fri, 9 Sep 2005 13:10:11 -0700 Subject: [PATCH 254/563] [PATCH] Update Documentation/DocBook/kernel-hacking.tmpl Update the hacking guide, before CONFIG_PREEMPT_RT goes in and it needs rewriting again. Changes include modernization of quotes, removal of most references to bottom halves (some mention required because we still use bh in places to mean softirq). It would be nice to have a discussion of sparse and various annotations. Please send patches straight to akpm. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (authored) Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/DocBook/kernel-hacking.tmpl | 310 ++++++++++------------ 1 file changed, 144 insertions(+), 166 deletions(-) diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl index 49a9ef82d575f..6367bba32d222 100644 --- a/Documentation/DocBook/kernel-hacking.tmpl +++ b/Documentation/DocBook/kernel-hacking.tmpl @@ -8,8 +8,7 @@ <authorgroup> <author> - <firstname>Paul</firstname> - <othername>Rusty</othername> + <firstname>Rusty</firstname> <surname>Russell</surname> <affiliation> <address> @@ -20,7 +19,7 @@ </authorgroup> <copyright> - <year>2001</year> + <year>2005</year> <holder>Rusty Russell</holder> </copyright> @@ -64,7 +63,7 @@ <chapter id="introduction"> <title>Introduction</title> <para> - Welcome, gentle reader, to Rusty's Unreliable Guide to Linux + Welcome, gentle reader, to Rusty's Remarkably Unreliable Guide to Linux Kernel Hacking. This document describes the common routines and general requirements for kernel code: its goal is to serve as a primer for Linux kernel development for experienced C @@ -96,13 +95,13 @@ <listitem> <para> - not associated with any process, serving a softirq, tasklet or bh; + not associated with any process, serving a softirq or tasklet; </para> </listitem> <listitem> <para> - running in kernel space, associated with a process; + running in kernel space, associated with a process (user context); </para> </listitem> @@ -114,11 +113,12 @@ </itemizedlist> <para> - There is a strict ordering between these: other than the last - category (userspace) each can only be pre-empted by those above. - For example, while a softirq is running on a CPU, no other - softirq will pre-empt it, but a hardware interrupt can. However, - any other CPUs in the system execute independently. + There is an ordering between these. The bottom two can preempt + each other, but above that is a strict hierarchy: each can only be + preempted by the ones above it. For example, while a softirq is + running on a CPU, no other softirq will preempt it, but a hardware + interrupt can. However, any other CPUs in the system execute + independently. </para> <para> @@ -130,10 +130,10 @@ <title>User Context</title> <para> - User context is when you are coming in from a system call or - other trap: you can sleep, and you own the CPU (except for - interrupts) until you call <function>schedule()</function>. - In other words, user context (unlike userspace) is not pre-emptable. + User context is when you are coming in from a system call or other + trap: like userspace, you can be preempted by more important tasks + and by interrupts. You can sleep, by calling + <function>schedule()</function>. </para> <note> @@ -153,7 +153,7 @@ <caution> <para> - Beware that if you have interrupts or bottom halves disabled + Beware that if you have preemption or softirqs disabled (see below), <function>in_interrupt()</function> will return a false positive. </para> @@ -168,10 +168,10 @@ <hardware>keyboard</hardware> are examples of real hardware which produce interrupts at any time. The kernel runs interrupt handlers, which services the hardware. The kernel - guarantees that this handler is never re-entered: if another + guarantees that this handler is never re-entered: if the same interrupt arrives, it is queued (or dropped). Because it disables interrupts, this handler has to be fast: frequently it - simply acknowledges the interrupt, marks a `software interrupt' + simply acknowledges the interrupt, marks a 'software interrupt' for execution and exits. </para> @@ -188,60 +188,52 @@ </sect1> <sect1 id="basics-softirqs"> - <title>Software Interrupt Context: Bottom Halves, Tasklets, softirqs</title> + <title>Software Interrupt Context: Softirqs and Tasklets</title> <para> Whenever a system call is about to return to userspace, or a - hardware interrupt handler exits, any `software interrupts' + hardware interrupt handler exits, any 'software interrupts' which are marked pending (usually by hardware interrupts) are run (<filename>kernel/softirq.c</filename>). </para> <para> Much of the real interrupt handling work is done here. Early in - the transition to <acronym>SMP</acronym>, there were only `bottom + the transition to <acronym>SMP</acronym>, there were only 'bottom halves' (BHs), which didn't take advantage of multiple CPUs. Shortly after we switched from wind-up computers made of match-sticks and snot, - we abandoned this limitation. + we abandoned this limitation and switched to 'softirqs'. </para> <para> <filename class="headerfile">include/linux/interrupt.h</filename> lists the - different BH's. No matter how many CPUs you have, no two BHs will run at - the same time. This made the transition to SMP simpler, but sucks hard for - scalable performance. A very important bottom half is the timer - BH (<filename class="headerfile">include/linux/timer.h</filename>): you - can register to have it call functions for you in a given length of time. + different softirqs. A very important softirq is the + timer softirq (<filename + class="headerfile">include/linux/timer.h</filename>): you can + register to have it call functions for you in a given length of + time. </para> <para> - 2.3.43 introduced softirqs, and re-implemented the (now - deprecated) BHs underneath them. Softirqs are fully-SMP - versions of BHs: they can run on as many CPUs at once as - required. This means they need to deal with any races in shared - data using their own locks. A bitmask is used to keep track of - which are enabled, so the 32 available softirqs should not be - used up lightly. (<emphasis>Yes</emphasis>, people will - notice). - </para> - - <para> - tasklets (<filename class="headerfile">include/linux/interrupt.h</filename>) - are like softirqs, except they are dynamically-registrable (meaning you - can have as many as you want), and they also guarantee that any tasklet - will only run on one CPU at any time, although different tasklets can - run simultaneously (unlike different BHs). + Softirqs are often a pain to deal with, since the same softirq + will run simultaneously on more than one CPU. For this reason, + tasklets (<filename + class="headerfile">include/linux/interrupt.h</filename>) are more + often used: they are dynamically-registrable (meaning you can have + as many as you want), and they also guarantee that any tasklet + will only run on one CPU at any time, although different tasklets + can run simultaneously. </para> <caution> <para> - The name `tasklet' is misleading: they have nothing to do with `tasks', + The name 'tasklet' is misleading: they have nothing to do with 'tasks', and probably more to do with some bad vodka Alexey Kuznetsov had at the time. </para> </caution> <para> - You can tell you are in a softirq (or bottom half, or tasklet) + You can tell you are in a softirq (or tasklet) using the <function>in_softirq()</function> macro (<filename class="headerfile">include/linux/interrupt.h</filename>). </para> @@ -288,11 +280,10 @@ <term>A rigid stack limit</term> <listitem> <para> - The kernel stack is about 6K in 2.2 (for most - architectures: it's about 14K on the Alpha), and shared - with interrupts so you can't use it all. Avoid deep - recursion and huge local arrays on the stack (allocate - them dynamically instead). + Depending on configuration options the kernel stack is about 3K to 6K for most 32-bit architectures: it's + about 14K on most 64-bit archs, and often shared with interrupts + so you can't use it all. Avoid deep recursion and huge local + arrays on the stack (allocate them dynamically instead). </para> </listitem> </varlistentry> @@ -339,7 +330,7 @@ asmlinkage long sys_mycall(int arg) <para> If all your routine does is read or write some parameter, consider - implementing a <function>sysctl</function> interface instead. + implementing a <function>sysfs</function> interface instead. </para> <para> @@ -417,7 +408,10 @@ cond_resched(); /* Will sleep */ </para> <para> - You will eventually lock up your box if you break these rules. + You should always compile your kernel + <symbol>CONFIG_DEBUG_SPINLOCK_SLEEP</symbol> on, and it will warn + you if you break these rules. If you <emphasis>do</emphasis> break + the rules, you will eventually lock up your box. </para> <para> @@ -515,8 +509,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); success). </para> </caution> - [Yes, this moronic interface makes me cringe. Please submit a - patch and become my hero --RR.] + [Yes, this moronic interface makes me cringe. The flamewar comes up every year or so. --RR.] </para> <para> The functions may sleep implicitly. This should never be called @@ -587,10 +580,11 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); </variablelist> <para> - If you see a <errorname>kmem_grow: Called nonatomically from int - </errorname> warning message you called a memory allocation function - from interrupt context without <constant>GFP_ATOMIC</constant>. - You should really fix that. Run, don't walk. + If you see a <errorname>sleeping function called from invalid + context</errorname> warning message, then maybe you called a + sleeping allocation function from interrupt context without + <constant>GFP_ATOMIC</constant>. You should really fix that. + Run, don't walk. </para> <para> @@ -639,16 +633,16 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); </sect1> <sect1 id="routines-udelay"> - <title><function>udelay()</function>/<function>mdelay()</function> + <title><function>mdelay()</function>/<function>udelay()</function> <filename class="headerfile">include/asm/delay.h</filename> <filename class="headerfile">include/linux/delay.h</filename> </title> <para> - The <function>udelay()</function> function can be used for small pauses. - Do not use large values with <function>udelay()</function> as you risk + The <function>udelay()</function> and <function>ndelay()</function> functions can be used for small pauses. + Do not use large values with them as you risk overflow - the helper function <function>mdelay()</function> is useful - here, or even consider <function>schedule_timeout()</function>. + here, or consider <function>msleep()</function>. </para> </sect1> @@ -698,8 +692,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); These routines disable soft interrupts on the local CPU, and restore them. They are reentrant; if soft interrupts were disabled before, they will still be disabled after this pair - of functions has been called. They prevent softirqs, tasklets - and bottom halves from running on the current CPU. + of functions has been called. They prevent softirqs and tasklets + from running on the current CPU. </para> </sect1> @@ -708,10 +702,16 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); <filename class="headerfile">include/asm/smp.h</filename></title> <para> - <function>smp_processor_id()</function> returns the current - processor number, between 0 and <symbol>NR_CPUS</symbol> (the - maximum number of CPUs supported by Linux, currently 32). These - values are not necessarily continuous. + <function>get_cpu()</function> disables preemption (so you won't + suddenly get moved to another CPU) and returns the current + processor number, between 0 and <symbol>NR_CPUS</symbol>. Note + that the CPU numbers are not necessarily continuous. You return + it again with <function>put_cpu()</function> when you are done. + </para> + <para> + If you know you cannot be preempted by another task (ie. you are + in interrupt context, or have preemption disabled) you can use + smp_processor_id(). </para> </sect1> @@ -722,19 +722,14 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); <para> After boot, the kernel frees up a special section; functions marked with <type>__init</type> and data structures marked with - <type>__initdata</type> are dropped after boot is complete (within - modules this directive is currently ignored). <type>__exit</type> + <type>__initdata</type> are dropped after boot is complete: similarly + modules discard this memory after initialization. <type>__exit</type> is used to declare a function which is only required on exit: the function will be dropped if this file is not compiled as a module. See the header file for use. Note that it makes no sense for a function marked with <type>__init</type> to be exported to modules with <function>EXPORT_SYMBOL()</function> - this will break. </para> - <para> - Static data structures marked as <type>__initdata</type> must be initialised - (as opposed to ordinary static data which is zeroed BSS) and cannot be - <type>const</type>. - </para> </sect1> @@ -762,9 +757,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); <para> The function can return a negative error number to cause module loading to fail (unfortunately, this has no effect if - the module is compiled into the kernel). For modules, this is - called in user context, with interrupts enabled, and the - kernel lock held, so it can sleep. + the module is compiled into the kernel). This function is + called in user context with interrupts enabled, so it can sleep. </para> </sect1> @@ -779,6 +773,34 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); reached zero. This function can also sleep, but cannot fail: everything must be cleaned up by the time it returns. </para> + + <para> + Note that this macro is optional: if it is not present, your + module will not be removable (except for 'rmmod -f'). + </para> + </sect1> + + <sect1 id="routines-module-use-counters"> + <title> <function>try_module_get()</function>/<function>module_put()</function> + <filename class="headerfile">include/linux/module.h</filename></title> + + <para> + These manipulate the module usage count, to protect against + removal (a module also can't be removed if another module uses one + of its exported symbols: see below). Before calling into module + code, you should call <function>try_module_get()</function> on + that module: if it fails, then the module is being removed and you + should act as if it wasn't there. Otherwise, you can safely enter + the module, and call <function>module_put()</function> when you're + finished. + </para> + + <para> + Most registerable structures have an + <structfield>owner</structfield> field, such as in the + <structname>file_operations</structname> structure. Set this field + to the macro <symbol>THIS_MODULE</symbol>. + </para> </sect1> <!-- add info on new-style module refcounting here --> @@ -821,7 +843,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); There is a macro to do this: <function>wait_event_interruptible()</function> - <filename class="headerfile">include/linux/sched.h</filename> The + <filename class="headerfile">include/linux/wait.h</filename> The first argument is the wait queue head, and the second is an expression which is evaluated; the macro returns <returnvalue>0</returnvalue> when this expression is true, or @@ -847,10 +869,11 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); <para> Call <function>wake_up()</function> - <filename class="headerfile">include/linux/sched.h</filename>;, + <filename class="headerfile">include/linux/wait.h</filename>;, which will wake up every process in the queue. The exception is if one has <constant>TASK_EXCLUSIVE</constant> set, in which case - the remainder of the queue will not be woken. + the remainder of the queue will not be woken. There are other variants + of this basic function available in the same header. </para> </sect1> </chapter> @@ -863,7 +886,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); first class of operations work on <type>atomic_t</type> <filename class="headerfile">include/asm/atomic.h</filename>; this - contains a signed integer (at least 24 bits long), and you must use + contains a signed integer (at least 32 bits long), and you must use these functions to manipulate or read atomic_t variables. <function>atomic_read()</function> and <function>atomic_set()</function> get and set the counter, @@ -882,13 +905,12 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); <para> Note that these functions are slower than normal arithmetic, and - so should not be used unnecessarily. On some platforms they - are much slower, like 32-bit Sparc where they use a spinlock. + so should not be used unnecessarily. </para> <para> - The second class of atomic operations is atomic bit operations on a - <type>long</type>, defined in + The second class of atomic operations is atomic bit operations on an + <type>unsigned long</type>, defined in <filename class="headerfile">include/linux/bitops.h</filename>. These operations generally take a pointer to the bit pattern, and a bit @@ -899,7 +921,7 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); <function>test_and_clear_bit()</function> and <function>test_and_change_bit()</function> do the same thing, except return true if the bit was previously set; these are - particularly useful for very simple locking. + particularly useful for atomically setting flags. </para> <para> @@ -907,12 +929,6 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); than BITS_PER_LONG. The resulting behavior is strange on big-endian platforms though so it is a good idea not to do this. </para> - - <para> - Note that the order of bits depends on the architecture, and in - particular, the bitfield passed to these operations must be at - least as large as a <type>long</type>. - </para> </chapter> <chapter id="symbols"> @@ -932,11 +948,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); <filename class="headerfile">include/linux/module.h</filename></title> <para> - This is the classic method of exporting a symbol, and it works - for both modules and non-modules. In the kernel all these - declarations are often bundled into a single file to help - genksyms (which searches source files for these declarations). - See the comment on genksyms and Makefiles below. + This is the classic method of exporting a symbol: dynamically + loaded modules will be able to use the symbol as normal. </para> </sect1> @@ -949,7 +962,8 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); symbols exported by <function>EXPORT_SYMBOL_GPL()</function> can only be seen by modules with a <function>MODULE_LICENSE()</function> that specifies a GPL - compatible license. + compatible license. It implies that the function is considered + an internal implementation issue, and not really an interface. </para> </sect1> </chapter> @@ -962,12 +976,13 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); <filename class="headerfile">include/linux/list.h</filename></title> <para> - There are three sets of linked-list routines in the kernel - headers, but this one seems to be winning out (and Linus has - used it). If you don't have some particular pressing need for - a single list, it's a good choice. In fact, I don't care - whether it's a good choice or not, just use it so we can get - rid of the others. + There used to be three sets of linked-list routines in the kernel + headers, but this one is the winner. If you don't have some + particular pressing need for a single list, it's a good choice. + </para> + + <para> + In particular, <function>list_for_each_entry</function> is useful. </para> </sect1> @@ -979,14 +994,13 @@ printk(KERN_INFO "my ip: %d.%d.%d.%d\n", NIPQUAD(ipaddress)); convention, and return <returnvalue>0</returnvalue> for success, and a negative error number (eg. <returnvalue>-EFAULT</returnvalue>) for failure. This can be - unintuitive at first, but it's fairly widespread in the networking - code, for example. + unintuitive at first, but it's fairly widespread in the kernel. </para> <para> - The filesystem code uses <function>ERR_PTR()</function> + Using <function>ERR_PTR()</function> - <filename class="headerfile">include/linux/fs.h</filename>; to + <filename class="headerfile">include/linux/err.h</filename>; to encode a negative error number into a pointer, and <function>IS_ERR()</function> and <function>PTR_ERR()</function> to get it back out again: avoids a separate pointer parameter for @@ -1040,7 +1054,7 @@ static struct block_device_operations opt_fops = { supported, due to lack of general use, but the following are considered standard (see the GCC info page section "C Extensions" for more details - Yes, really the info page, the - man page is only a short summary of the stuff in info): + man page is only a short summary of the stuff in info). </para> <itemizedlist> <listitem> @@ -1091,7 +1105,7 @@ static struct block_device_operations opt_fops = { </listitem> <listitem> <para> - Function names as strings (__FUNCTION__) + Function names as strings (__func__). </para> </listitem> <listitem> @@ -1164,63 +1178,35 @@ static struct block_device_operations opt_fops = { <listitem> <para> Usually you want a configuration option for your kernel hack. - Edit <filename>Config.in</filename> in the appropriate directory - (but under <filename>arch/</filename> it's called - <filename>config.in</filename>). The Config Language used is not - bash, even though it looks like bash; the safe way is to use only - the constructs that you already see in - <filename>Config.in</filename> files (see - <filename>Documentation/kbuild/kconfig-language.txt</filename>). - It's good to run "make xconfig" at least once to test (because - it's the only one with a static parser). - </para> - - <para> - Variables which can be Y or N use <type>bool</type> followed by a - tagline and the config define name (which must start with - CONFIG_). The <type>tristate</type> function is the same, but - allows the answer M (which defines - <symbol>CONFIG_foo_MODULE</symbol> in your source, instead of - <symbol>CONFIG_FOO</symbol>) if <symbol>CONFIG_MODULES</symbol> - is enabled. + Edit <filename>Kconfig</filename> in the appropriate directory. + The Config language is simple to use by cut and paste, and there's + complete documentation in + <filename>Documentation/kbuild/kconfig-language.txt</filename>. </para> <para> You may well want to make your CONFIG option only visible if <symbol>CONFIG_EXPERIMENTAL</symbol> is enabled: this serves as a warning to users. There many other fancy things you can do: see - the various <filename>Config.in</filename> files for ideas. + the various <filename>Kconfig</filename> files for ideas. </para> - </listitem> - <listitem> <para> - Edit the <filename>Makefile</filename>: the CONFIG variables are - exported here so you can conditionalize compilation with `ifeq'. - If your file exports symbols then add the names to - <varname>export-objs</varname> so that genksyms will find them. - <caution> - <para> - There is a restriction on the kernel build system that objects - which export symbols must have globally unique names. - If your object does not have a globally unique name then the - standard fix is to move the - <function>EXPORT_SYMBOL()</function> statements to their own - object with a unique name. - This is why several systems have separate exporting objects, - usually suffixed with ksyms. - </para> - </caution> + In your description of the option, make sure you address both the + expert user and the user who knows nothing about your feature. Mention + incompatibilities and issues here. <emphasis> Definitely + </emphasis> end your description with <quote> if in doubt, say N + </quote> (or, occasionally, `Y'); this is for people who have no + idea what you are talking about. </para> </listitem> <listitem> <para> - Document your option in Documentation/Configure.help. Mention - incompatibilities and issues here. <emphasis> Definitely - </emphasis> end your description with <quote> if in doubt, say N - </quote> (or, occasionally, `Y'); this is for people who have no - idea what you are talking about. + Edit the <filename>Makefile</filename>: the CONFIG variables are + exported here so you can usually just add a "obj-$(CONFIG_xxx) += + xxx.o" line. The syntax is documented in + <filename>Documentation/kbuild/makefiles.txt</filename>. </para> </listitem> @@ -1253,20 +1239,12 @@ static struct block_device_operations opt_fops = { </para> <para> - <filename>include/linux/brlock.h:</filename> + <filename>include/asm-i386/delay.h:</filename> </para> <programlisting> -extern inline void br_read_lock (enum brlock_indices idx) -{ - /* - * This causes a link-time bug message if an - * invalid index is used: - */ - if (idx >= __BR_END) - __br_lock_usage_bug(); - - read_lock(&__brlock_array[smp_processor_id()][idx]); -} +#define ndelay(n) (__builtin_constant_p(n) ? \ + ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ + __ndelay(n)) </programlisting> <para> -- GitLab From 754c79768eed257dabd922b85cb9271822e50794 Mon Sep 17 00:00:00 2001 From: Jesper Juhl <jesper.juhl@gmail.com> Date: Fri, 9 Sep 2005 13:10:12 -0700 Subject: [PATCH 255/563] [PATCH] Documentation: how to apply patches for various trees Add a new document describing the major kernel trees and how to apply their patches. Signed-off-by: Jesper Juhl <jesper.juhl@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/00-INDEX | 2 + Documentation/applying-patches.txt | 439 +++++++++++++++++++++++++++++ 2 files changed, 441 insertions(+) create mode 100644 Documentation/applying-patches.txt diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index f28a24e0279b4..f6de52b010591 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -46,6 +46,8 @@ SubmittingPatches - procedure to get a source patch included into the kernel tree. VGA-softcursor.txt - how to change your VGA cursor from a blinking underscore. +applying-patches.txt + - description of various trees and how to apply their patches. arm/ - directory with info about Linux on the ARM architecture. basic_profiling.txt diff --git a/Documentation/applying-patches.txt b/Documentation/applying-patches.txt new file mode 100644 index 0000000000000..681e426e24821 --- /dev/null +++ b/Documentation/applying-patches.txt @@ -0,0 +1,439 @@ + + Applying Patches To The Linux Kernel + ------------------------------------ + + (Written by Jesper Juhl, August 2005) + + + +A frequently asked question on the Linux Kernel Mailing List is how to apply +a patch to the kernel or, more specifically, what base kernel a patch for +one of the many trees/branches should be applied to. Hopefully this document +will explain this to you. + +In addition to explaining how to apply and revert patches, a brief +description of the different kernel trees (and examples of how to apply +their specific patches) is also provided. + + +What is a patch? +--- + A patch is a small text document containing a delta of changes between two +different versions of a source tree. Patches are created with the `diff' +program. +To correctly apply a patch you need to know what base it was generated from +and what new version the patch will change the source tree into. These +should both be present in the patch file metadata or be possible to deduce +from the filename. + + +How do I apply or revert a patch? +--- + You apply a patch with the `patch' program. The patch program reads a diff +(or patch) file and makes the changes to the source tree described in it. + +Patches for the Linux kernel are generated relative to the parent directory +holding the kernel source dir. + +This means that paths to files inside the patch file contain the name of the +kernel source directories it was generated against (or some other directory +names like "a/" and "b/"). +Since this is unlikely to match the name of the kernel source dir on your +local machine (but is often useful info to see what version an otherwise +unlabeled patch was generated against) you should change into your kernel +source directory and then strip the first element of the path from filenames +in the patch file when applying it (the -p1 argument to `patch' does this). + +To revert a previously applied patch, use the -R argument to patch. +So, if you applied a patch like this: + patch -p1 < ../patch-x.y.z + +You can revert (undo) it like this: + patch -R -p1 < ../patch-x.y.z + + +How do I feed a patch/diff file to `patch'? +--- + This (as usual with Linux and other UNIX like operating systems) can be +done in several different ways. +In all the examples below I feed the file (in uncompressed form) to patch +via stdin using the following syntax: + patch -p1 < path/to/patch-x.y.z + +If you just want to be able to follow the examples below and don't want to +know of more than one way to use patch, then you can stop reading this +section here. + +Patch can also get the name of the file to use via the -i argument, like +this: + patch -p1 -i path/to/patch-x.y.z + +If your patch file is compressed with gzip or bzip2 and you don't want to +uncompress it before applying it, then you can feed it to patch like this +instead: + zcat path/to/patch-x.y.z.gz | patch -p1 + bzcat path/to/patch-x.y.z.bz2 | patch -p1 + +If you wish to uncompress the patch file by hand first before applying it +(what I assume you've done in the examples below), then you simply run +gunzip or bunzip2 on the file - like this: + gunzip patch-x.y.z.gz + bunzip2 patch-x.y.z.bz2 + +Which will leave you with a plain text patch-x.y.z file that you can feed to +patch via stdin or the -i argument, as you prefer. + +A few other nice arguments for patch are -s which causes patch to be silent +except for errors which is nice to prevent errors from scrolling out of the +screen too fast, and --dry-run which causes patch to just print a listing of +what would happen, but doesn't actually make any changes. Finally --verbose +tells patch to print more information about the work being done. + + +Common errors when patching +--- + When patch applies a patch file it attempts to verify the sanity of the +file in different ways. +Checking that the file looks like a valid patch file, checking the code +around the bits being modified matches the context provided in the patch are +just two of the basic sanity checks patch does. + +If patch encounters something that doesn't look quite right it has two +options. It can either refuse to apply the changes and abort or it can try +to find a way to make the patch apply with a few minor changes. + +One example of something that's not 'quite right' that patch will attempt to +fix up is if all the context matches, the lines being changed match, but the +line numbers are different. This can happen, for example, if the patch makes +a change in the middle of the file but for some reasons a few lines have +been added or removed near the beginning of the file. In that case +everything looks good it has just moved up or down a bit, and patch will +usually adjust the line numbers and apply the patch. + +Whenever patch applies a patch that it had to modify a bit to make it fit +it'll tell you about it by saying the patch applied with 'fuzz'. +You should be wary of such changes since even though patch probably got it +right it doesn't /always/ get it right, and the result will sometimes be +wrong. + +When patch encounters a change that it can't fix up with fuzz it rejects it +outright and leaves a file with a .rej extension (a reject file). You can +read this file to see exactely what change couldn't be applied, so you can +go fix it up by hand if you wish. + +If you don't have any third party patches applied to your kernel source, but +only patches from kernel.org and you apply the patches in the correct order, +and have made no modifications yourself to the source files, then you should +never see a fuzz or reject message from patch. If you do see such messages +anyway, then there's a high risk that either your local source tree or the +patch file is corrupted in some way. In that case you should probably try +redownloading the patch and if things are still not OK then you'd be advised +to start with a fresh tree downloaded in full from kernel.org. + +Let's look a bit more at some of the messages patch can produce. + +If patch stops and presents a "File to patch:" prompt, then patch could not +find a file to be patched. Most likely you forgot to specify -p1 or you are +in the wrong directory. Less often, you'll find patches that need to be +applied with -p0 instead of -p1 (reading the patch file should reveal if +this is the case - if so, then this is an error by the person who created +the patch but is not fatal). + +If you get "Hunk #2 succeeded at 1887 with fuzz 2 (offset 7 lines)." or a +message similar to that, then it means that patch had to adjust the location +of the change (in this example it needed to move 7 lines from where it +expected to make the change to make it fit). +The resulting file may or may not be OK, depending on the reason the file +was different than expected. +This often happens if you try to apply a patch that was generated against a +different kernel version than the one you are trying to patch. + +If you get a message like "Hunk #3 FAILED at 2387.", then it means that the +patch could not be applied correctly and the patch program was unable to +fuzz its way through. This will generate a .rej file with the change that +caused the patch to fail and also a .orig file showing you the original +content that couldn't be changed. + +If you get "Reversed (or previously applied) patch detected! Assume -R? [n]" +then patch detected that the change contained in the patch seems to have +already been made. +If you actually did apply this patch previously and you just re-applied it +in error, then just say [n]o and abort this patch. If you applied this patch +previously and actually intended to revert it, but forgot to specify -R, +then you can say [y]es here to make patch revert it for you. +This can also happen if the creator of the patch reversed the source and +destination directories when creating the patch, and in that case reverting +the patch will in fact apply it. + +A message similar to "patch: **** unexpected end of file in patch" or "patch +unexpectedly ends in middle of line" means that patch could make no sense of +the file you fed to it. Either your download is broken or you tried to feed +patch a compressed patch file without uncompressing it first. + +As I already mentioned above, these errors should never happen if you apply +a patch from kernel.org to the correct version of an unmodified source tree. +So if you get these errors with kernel.org patches then you should probably +assume that either your patch file or your tree is broken and I'd advice you +to start over with a fresh download of a full kernel tree and the patch you +wish to apply. + + +Are there any alternatives to `patch'? +--- + Yes there are alternatives. You can use the `interdiff' program +(http://cyberelk.net/tim/patchutils/) to generate a patch representing the +differences between two patches and then apply the result. +This will let you move from something like 2.6.12.2 to 2.6.12.3 in a single +step. The -z flag to interdiff will even let you feed it patches in gzip or +bzip2 compressed form directly without the use of zcat or bzcat or manual +decompression. + +Here's how you'd go from 2.6.12.2 to 2.6.12.3 in a single step: + interdiff -z ../patch-2.6.12.2.bz2 ../patch-2.6.12.3.gz | patch -p1 + +Although interdiff may save you a step or two you are generally advised to +do the additional steps since interdiff can get things wrong in some cases. + + Another alternative is `ketchup', which is a python script for automatic +downloading and applying of patches (http://www.selenic.com/ketchup/). + +Other nice tools are diffstat which shows a summary of changes made by a +patch, lsdiff which displays a short listing of affected files in a patch +file, along with (optionally) the line numbers of the start of each patch +and grepdiff which displays a list of the files modified by a patch where +the patch contains a given regular expression. + + +Where can I download the patches? +--- + The patches are available at http://kernel.org/ +Most recent patches are linked from the front page, but they also have +specific homes. + +The 2.6.x.y (-stable) and 2.6.x patches live at + ftp://ftp.kernel.org/pub/linux/kernel/v2.6/ + +The -rc patches live at + ftp://ftp.kernel.org/pub/linux/kernel/v2.6/testing/ + +The -git patches live at + ftp://ftp.kernel.org/pub/linux/kernel/v2.6/snapshots/ + +The -mm kernels live at + ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/ + +In place of ftp.kernel.org you can use ftp.cc.kernel.org, where cc is a +country code. This way you'll be downloading from a mirror site that's most +likely geographically closer to you, resulting in faster downloads for you, +less bandwidth used globally and less load on the main kernel.org servers - +these are good things, do use mirrors when possible. + + +The 2.6.x kernels +--- + These are the base stable releases released by Linus. The highest numbered +release is the most recent. + +If regressions or other serious flaws are found then a -stable fix patch +will be released (see below) on top of this base. Once a new 2.6.x base +kernel is released, a patch is made available that is a delta between the +previous 2.6.x kernel and the new one. + +To apply a patch moving from 2.6.11 to 2.6.12 you'd do the following (note +that such patches do *NOT* apply on top of 2.6.x.y kernels but on top of the +base 2.6.x kernel - if you need to move from 2.6.x.y to 2.6.x+1 you need to +first revert the 2.6.x.y patch). + +Here are some examples: + +# moving from 2.6.11 to 2.6.12 +$ cd ~/linux-2.6.11 # change to kernel source dir +$ patch -p1 < ../patch-2.6.12 # apply the 2.6.12 patch +$ cd .. +$ mv linux-2.6.11 linux-2.6.12 # rename source dir + +# moving from 2.6.11.1 to 2.6.12 +$ cd ~/linux-2.6.11.1 # change to kernel source dir +$ patch -p1 -R < ../patch-2.6.11.1 # revert the 2.6.11.1 patch + # source dir is now 2.6.11 +$ patch -p1 < ../patch-2.6.12 # apply new 2.6.12 patch +$ cd .. +$ mv linux-2.6.11.1 inux-2.6.12 # rename source dir + + +The 2.6.x.y kernels +--- + Kernels with 4 digit versions are -stable kernels. They contain small(ish) +critical fixes for security problems or significant regressions discovered +in a given 2.6.x kernel. + +This is the recommended branch for users who want the most recent stable +kernel and are not interested in helping test development/experimental +versions. + +If no 2.6.x.y kernel is available, then the highest numbered 2.6.x kernel is +the current stable kernel. + +These patches are not incremental, meaning that for example the 2.6.12.3 +patch does not apply on top of the 2.6.12.2 kernel source, but rather on top +of the base 2.6.12 kernel source. +So, in order to apply the 2.6.12.3 patch to your existing 2.6.12.2 kernel +source you have to first back out the 2.6.12.2 patch (so you are left with a +base 2.6.12 kernel source) and then apply the new 2.6.12.3 patch. + +Here's a small example: + +$ cd ~/linux-2.6.12.2 # change into the kernel source dir +$ patch -p1 -R < ../patch-2.6.12.2 # revert the 2.6.12.2 patch +$ patch -p1 < ../patch-2.6.12.3 # apply the new 2.6.12.3 patch +$ cd .. +$ mv linux-2.6.12.2 linux-2.6.12.3 # rename the kernel source dir + + +The -rc kernels +--- + These are release-candidate kernels. These are development kernels released +by Linus whenever he deems the current git (the kernel's source management +tool) tree to be in a reasonably sane state adequate for testing. + +These kernels are not stable and you should expect occasional breakage if +you intend to run them. This is however the most stable of the main +development branches and is also what will eventually turn into the next +stable kernel, so it is important that it be tested by as many people as +possible. + +This is a good branch to run for people who want to help out testing +development kernels but do not want to run some of the really experimental +stuff (such people should see the sections about -git and -mm kernels below). + +The -rc patches are not incremental, they apply to a base 2.6.x kernel, just +like the 2.6.x.y patches described above. The kernel version before the -rcN +suffix denotes the version of the kernel that this -rc kernel will eventually +turn into. +So, 2.6.13-rc5 means that this is the fifth release candidate for the 2.6.13 +kernel and the patch should be applied on top of the 2.6.12 kernel source. + +Here are 3 examples of how to apply these patches: + +# first an example of moving from 2.6.12 to 2.6.13-rc3 +$ cd ~/linux-2.6.12 # change into the 2.6.12 source dir +$ patch -p1 < ../patch-2.6.13-rc3 # apply the 2.6.13-rc3 patch +$ cd .. +$ mv linux-2.6.12 linux-2.6.13-rc3 # rename the source dir + +# now let's move from 2.6.13-rc3 to 2.6.13-rc5 +$ cd ~/linux-2.6.13-rc3 # change into the 2.6.13-rc3 dir +$ patch -p1 -R < ../patch-2.6.13-rc3 # revert the 2.6.13-rc3 patch +$ patch -p1 < ../patch-2.6.13-rc5 # apply the new 2.6.13-rc5 patch +$ cd .. +$ mv linux-2.6.13-rc3 linux-2.6.13-rc5 # rename the source dir + +# finally let's try and move from 2.6.12.3 to 2.6.13-rc5 +$ cd ~/linux-2.6.12.3 # change to the kernel source dir +$ patch -p1 -R < ../patch-2.6.12.3 # revert the 2.6.12.3 patch +$ patch -p1 < ../patch-2.6.13-rc5 # apply new 2.6.13-rc5 patch +$ cd .. +$ mv linux-2.6.12.3 linux-2.6.13-rc5 # rename the kernel source dir + + +The -git kernels +--- + These are daily snapshots of Linus' kernel tree (managed in a git +repository, hence the name). + +These patches are usually released daily and represent the current state of +Linus' tree. They are more experimental than -rc kernels since they are +generated automatically without even a cursory glance to see if they are +sane. + +-git patches are not incremental and apply either to a base 2.6.x kernel or +a base 2.6.x-rc kernel - you can see which from their name. +A patch named 2.6.12-git1 applies to the 2.6.12 kernel source and a patch +named 2.6.13-rc3-git2 applies to the source of the 2.6.13-rc3 kernel. + +Here are some examples of how to apply these patches: + +# moving from 2.6.12 to 2.6.12-git1 +$ cd ~/linux-2.6.12 # change to the kernel source dir +$ patch -p1 < ../patch-2.6.12-git1 # apply the 2.6.12-git1 patch +$ cd .. +$ mv linux-2.6.12 linux-2.6.12-git1 # rename the kernel source dir + +# moving from 2.6.12-git1 to 2.6.13-rc2-git3 +$ cd ~/linux-2.6.12-git1 # change to the kernel source dir +$ patch -p1 -R < ../patch-2.6.12-git1 # revert the 2.6.12-git1 patch + # we now have a 2.6.12 kernel +$ patch -p1 < ../patch-2.6.13-rc2 # apply the 2.6.13-rc2 patch + # the kernel is now 2.6.13-rc2 +$ patch -p1 < ../patch-2.6.13-rc2-git3 # apply the 2.6.13-rc2-git3 patch + # the kernel is now 2.6.13-rc2-git3 +$ cd .. +$ mv linux-2.6.12-git1 linux-2.6.13-rc2-git3 # rename source dir + + +The -mm kernels +--- + These are experimental kernels released by Andrew Morton. + +The -mm tree serves as a sort of proving ground for new features and other +experimental patches. +Once a patch has proved its worth in -mm for a while Andrew pushes it on to +Linus for inclusion in mainline. + +Although it's encouraged that patches flow to Linus via the -mm tree, this +is not always enforced. +Subsystem maintainers (or individuals) sometimes push their patches directly +to Linus, even though (or after) they have been merged and tested in -mm (or +sometimes even without prior testing in -mm). + +You should generally strive to get your patches into mainline via -mm to +ensure maximum testing. + +This branch is in constant flux and contains many experimental features, a +lot of debugging patches not appropriate for mainline etc and is the most +experimental of the branches described in this document. + +These kernels are not appropriate for use on systems that are supposed to be +stable and they are more risky to run than any of the other branches (make +sure you have up-to-date backups - that goes for any experimental kernel but +even more so for -mm kernels). + +These kernels in addition to all the other experimental patches they contain +usually also contain any changes in the mainline -git kernels available at +the time of release. + +Testing of -mm kernels is greatly appreciated since the whole point of the +tree is to weed out regressions, crashes, data corruption bugs, build +breakage (and any other bug in general) before changes are merged into the +more stable mainline Linus tree. +But testers of -mm should be aware that breakage in this tree is more common +than in any other tree. + +The -mm kernels are not released on a fixed schedule, but usually a few -mm +kernels are released in between each -rc kernel (1 to 3 is common). +The -mm kernels apply to either a base 2.6.x kernel (when no -rc kernels +have been released yet) or to a Linus -rc kernel. + +Here are some examples of applying the -mm patches: + +# moving from 2.6.12 to 2.6.12-mm1 +$ cd ~/linux-2.6.12 # change to the 2.6.12 source dir +$ patch -p1 < ../2.6.12-mm1 # apply the 2.6.12-mm1 patch +$ cd .. +$ mv linux-2.6.12 linux-2.6.12-mm1 # rename the source appropriately + +# moving from 2.6.12-mm1 to 2.6.13-rc3-mm3 +$ cd ~/linux-2.6.12-mm1 +$ patch -p1 -R < ../2.6.12-mm1 # revert the 2.6.12-mm1 patch + # we now have a 2.6.12 source +$ patch -p1 < ../patch-2.6.13-rc3 # apply the 2.6.13-rc3 patch + # we now have a 2.6.13-rc3 source +$ patch -p1 < ../2.6.13-rc3-mm3 # apply the 2.6.13-rc3-mm3 patch +$ cd .. +$ mv linux-2.6.12-mm1 linux-2.6.13-rc3-mm3 # rename the source dir + + +This concludes this list of explanations of the various kernel trees and I +hope you are now crystal clear on how to apply the various patches and help +testing the kernel. + -- GitLab From ddb99f3d35b178f0715aab2f9d9ab25f61814347 Mon Sep 17 00:00:00 2001 From: Pierre Ossman <drzeus@drzeus.cx> Date: Fri, 9 Sep 2005 13:10:13 -0700 Subject: [PATCH 256/563] [PATCH] ISA DMA API documentation Documentation for how the ISA DMA controller is handled in the kernel. Signed-off-by: Pierre Ossman <drzeus@drzeus.cx> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/DMA-ISA-LPC.txt | 151 ++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 Documentation/DMA-ISA-LPC.txt diff --git a/Documentation/DMA-ISA-LPC.txt b/Documentation/DMA-ISA-LPC.txt new file mode 100644 index 0000000000000..705f6be92bdbf --- /dev/null +++ b/Documentation/DMA-ISA-LPC.txt @@ -0,0 +1,151 @@ + DMA with ISA and LPC devices + ============================ + + Pierre Ossman <drzeus@drzeus.cx> + +This document describes how to do DMA transfers using the old ISA DMA +controller. Even though ISA is more or less dead today the LPC bus +uses the same DMA system so it will be around for quite some time. + +Part I - Headers and dependencies +--------------------------------- + +To do ISA style DMA you need to include two headers: + +#include <linux/dma-mapping.h> +#include <asm/dma.h> + +The first is the generic DMA API used to convert virtual addresses to +physical addresses (see Documentation/DMA-API.txt for details). + +The second contains the routines specific to ISA DMA transfers. Since +this is not present on all platforms make sure you construct your +Kconfig to be dependent on ISA_DMA_API (not ISA) so that nobody tries +to build your driver on unsupported platforms. + +Part II - Buffer allocation +--------------------------- + +The ISA DMA controller has some very strict requirements on which +memory it can access so extra care must be taken when allocating +buffers. + +(You usually need a special buffer for DMA transfers instead of +transferring directly to and from your normal data structures.) + +The DMA-able address space is the lowest 16 MB of _physical_ memory. +Also the transfer block may not cross page boundaries (which are 64 +or 128 KiB depending on which channel you use). + +In order to allocate a piece of memory that satisfies all these +requirements you pass the flag GFP_DMA to kmalloc. + +Unfortunately the memory available for ISA DMA is scarce so unless you +allocate the memory during boot-up it's a good idea to also pass +__GFP_REPEAT and __GFP_NOWARN to make the allocater try a bit harder. + +(This scarcity also means that you should allocate the buffer as +early as possible and not release it until the driver is unloaded.) + +Part III - Address translation +------------------------------ + +To translate the virtual address to a physical use the normal DMA +API. Do _not_ use isa_virt_to_phys() even though it does the same +thing. The reason for this is that the function isa_virt_to_phys() +will require a Kconfig dependency to ISA, not just ISA_DMA_API which +is really all you need. Remember that even though the DMA controller +has its origins in ISA it is used elsewhere. + +Note: x86_64 had a broken DMA API when it came to ISA but has since +been fixed. If your arch has problems then fix the DMA API instead of +reverting to the ISA functions. + +Part IV - Channels +------------------ + +A normal ISA DMA controller has 8 channels. The lower four are for +8-bit transfers and the upper four are for 16-bit transfers. + +(Actually the DMA controller is really two separate controllers where +channel 4 is used to give DMA access for the second controller (0-3). +This means that of the four 16-bits channels only three are usable.) + +You allocate these in a similar fashion as all basic resources: + +extern int request_dma(unsigned int dmanr, const char * device_id); +extern void free_dma(unsigned int dmanr); + +The ability to use 16-bit or 8-bit transfers is _not_ up to you as a +driver author but depends on what the hardware supports. Check your +specs or test different channels. + +Part V - Transfer data +---------------------- + +Now for the good stuff, the actual DMA transfer. :) + +Before you use any ISA DMA routines you need to claim the DMA lock +using claim_dma_lock(). The reason is that some DMA operations are +not atomic so only one driver may fiddle with the registers at a +time. + +The first time you use the DMA controller you should call +clear_dma_ff(). This clears an internal register in the DMA +controller that is used for the non-atomic operations. As long as you +(and everyone else) uses the locking functions then you only need to +reset this once. + +Next, you tell the controller in which direction you intend to do the +transfer using set_dma_mode(). Currently you have the options +DMA_MODE_READ and DMA_MODE_WRITE. + +Set the address from where the transfer should start (this needs to +be 16-bit aligned for 16-bit transfers) and how many bytes to +transfer. Note that it's _bytes_. The DMA routines will do all the +required translation to values that the DMA controller understands. + +The final step is enabling the DMA channel and releasing the DMA +lock. + +Once the DMA transfer is finished (or timed out) you should disable +the channel again. You should also check get_dma_residue() to make +sure that all data has been transfered. + +Example: + +int flags, residue; + +flags = claim_dma_lock(); + +clear_dma_ff(); + +set_dma_mode(channel, DMA_MODE_WRITE); +set_dma_addr(channel, phys_addr); +set_dma_count(channel, num_bytes); + +dma_enable(channel); + +release_dma_lock(flags); + +while (!device_done()); + +flags = claim_dma_lock(); + +dma_disable(channel); + +residue = dma_get_residue(channel); +if (residue != 0) + printk(KERN_ERR "driver: Incomplete DMA transfer!" + " %d bytes left!\n", residue); + +release_dma_lock(flags); + +Part VI - Suspend/resume +------------------------ + +It is the driver's responsibility to make sure that the machine isn't +suspended while a DMA transfer is in progress. Also, all DMA settings +are lost when the system suspends so if your driver relies on the DMA +controller being in a certain state then you have to restore these +registers upon resume. -- GitLab From af97c7220a0376beed827e72e3bb27731af7109d Mon Sep 17 00:00:00 2001 From: Chuck Ebbert <76306.1226@compuserve.com> Date: Fri, 9 Sep 2005 13:10:15 -0700 Subject: [PATCH 257/563] [PATCH] docs: fix misinformation about overcommit_memory Someone complained about the docs for vm_overcommit_memory being wrong. This patch copies the text from the vm documentation into procfs. Signed-off-by: Chuck Ebbert <76306.1226@compuserve.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/filesystems/proc.txt | 42 +++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 5024ba7a592c0..d4773565ea2f2 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1241,16 +1241,38 @@ swap-intensive. overcommit_memory ----------------- -This file contains one value. The following algorithm is used to decide if -there's enough memory: if the value of overcommit_memory is positive, then -there's always enough memory. This is a useful feature, since programs often -malloc() huge amounts of memory 'just in case', while they only use a small -part of it. Leaving this value at 0 will lead to the failure of such a huge -malloc(), when in fact the system has enough memory for the program to run. - -On the other hand, enabling this feature can cause you to run out of memory -and thrash the system to death, so large and/or important servers will want to -set this value to 0. +Controls overcommit of system memory, possibly allowing processes +to allocate (but not use) more memory than is actually available. + + +0 - Heuristic overcommit handling. Obvious overcommits of + address space are refused. Used for a typical system. It + ensures a seriously wild allocation fails while allowing + overcommit to reduce swap usage. root is allowed to + allocate slighly more memory in this mode. This is the + default. + +1 - Always overcommit. Appropriate for some scientific + applications. + +2 - Don't overcommit. The total address space commit + for the system is not permitted to exceed swap plus a + configurable percentage (default is 50) of physical RAM. + Depending on the percentage you use, in most situations + this means a process will not be killed while attempting + to use already-allocated memory but will receive errors + on memory allocation as appropriate. + +overcommit_ratio +---------------- + +Percentage of physical memory size to include in overcommit calculations +(see above.) + +Memory allocation limit = swapspace + physmem * (overcommit_ratio / 100) + + swapspace = total size of all swap areas + physmem = size of physical memory in system nr_hugepages and hugetlb_shm_group ---------------------------------- -- GitLab From 80e93effce55044c5a7fa96e8b313640a80bd4e9 Mon Sep 17 00:00:00 2001 From: Pekka Enberg <penberg@cs.helsinki.fi> Date: Fri, 9 Sep 2005 13:10:16 -0700 Subject: [PATCH 258/563] [PATCH] update kfree, vfree, and vunmap kerneldoc This patch clarifies NULL handling of kfree() and vfree(). I addition, wording of calling context restriction for vfree() and vunmap() are changed from "may not" to "must not." Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi> Acked-by: Manfred Spraul <manfred@colorfullife.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- mm/slab.c | 2 ++ mm/vmalloc.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index a041c5378dfa5..05a391059fe1d 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2998,6 +2998,8 @@ EXPORT_SYMBOL(kzalloc); * kfree - free previously allocated memory * @objp: pointer returned by kmalloc. * + * If @objp is NULL, no operation is performed. + * * Don't free memory not originally allocated by kmalloc() * or you will run into trouble. */ diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 67b358e57ef67..13c3d82968ae2 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -332,9 +332,10 @@ void __vunmap(void *addr, int deallocate_pages) * @addr: memory base address * * Free the virtually contiguous memory area starting at @addr, as - * obtained from vmalloc(), vmalloc_32() or __vmalloc(). + * obtained from vmalloc(), vmalloc_32() or __vmalloc(). If @addr is + * NULL, no operation is performed. * - * May not be called in interrupt context. + * Must not be called in interrupt context. */ void vfree(void *addr) { @@ -352,7 +353,7 @@ EXPORT_SYMBOL(vfree); * Free the virtually contiguous memory area starting at @addr, * which was created from the page array passed to vmap(). * - * May not be called in interrupt context. + * Must not be called in interrupt context. */ void vunmap(void *addr) { -- GitLab From 9d01a82e46a8dd18233121a6bc140e5576649583 Mon Sep 17 00:00:00 2001 From: Martin Waitz <tali@admingilde.org> Date: Fri, 9 Sep 2005 13:10:17 -0700 Subject: [PATCH 259/563] [PATCH] DocBook: fix kernel-api documentation generation This patch changes a macro definition so that kernel-doc can understand it. Signed-off-by: Martin Waitz <tali@admingilde.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/sound/pcm.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 389e8ebe9c191..d6361dab03708 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -910,11 +910,10 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format); * Returns 1 if the given PCM format is CPU-endian, 0 if * opposite, or a negative error code if endian not specified. */ -/* int snd_pcm_format_cpu_endian(snd_pcm_format_t format); */ #ifdef SNDRV_LITTLE_ENDIAN -#define snd_pcm_format_cpu_endian snd_pcm_format_little_endian +#define snd_pcm_format_cpu_endian(format) snd_pcm_format_little_endian(format) #else -#define snd_pcm_format_cpu_endian snd_pcm_format_big_endian +#define snd_pcm_format_cpu_endian(format) snd_pcm_format_big_endian(format) #endif int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */ int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ -- GitLab From 952b649272f96d58817be889ed4b932f638a4dbe Mon Sep 17 00:00:00 2001 From: Vivek Goyal <vgoyal@in.ibm.com> Date: Fri, 9 Sep 2005 13:10:19 -0700 Subject: [PATCH 260/563] [PATCH] Kdump: Documentation Update There are minor changes in command line options in kexec-tools for kdump. This patch updates the documentation to reflect those changes. Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/kdump/kdump.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt index 7ff213f4becd3..1f5f7d28c9e6b 100644 --- a/Documentation/kdump/kdump.txt +++ b/Documentation/kdump/kdump.txt @@ -39,8 +39,7 @@ SETUP and apply http://lse.sourceforge.net/kdump/patches/kexec-tools-1.101-kdump.patch and after that build the source. -2) Download and build the appropriate (latest) kexec/kdump (-mm) kernel - patchset and apply it to the vanilla kernel tree. +2) Download and build the appropriate (2.6.13-rc1 onwards) vanilla kernel. Two kernels need to be built in order to get this feature working. @@ -84,15 +83,16 @@ SETUP 4) Load the second kernel to be booted using: - kexec -p <second-kernel> --crash-dump --args-linux --append="root=<root-dev> - init 1 irqpoll" + kexec -p <second-kernel> --args-linux --elf32-core-headers + --append="root=<root-dev> init 1 irqpoll" Note: i) <second-kernel> has to be a vmlinux image. bzImage will not work, as of now. - ii) By default ELF headers are stored in ELF32 format (for i386). This - is sufficient to represent the physical memory up to 4GB. To store - headers in ELF64 format, specifiy "--elf64-core-headers" on the - kexec command line additionally. + ii) By default ELF headers are stored in ELF64 format. Option + --elf32-core-headers forces generation of ELF32 headers. gdb can + not open ELF64 headers on 32 bit systems. So creating ELF32 + headers can come handy for users who have got non-PAE systems and + hence have memory less than 4GB. iii) Specify "irqpoll" as command line parameter. This reduces driver initialization failures in second kernel due to shared interrupts. -- GitLab From 5ea626aac1ab9a34aed62dc651070cf1e5134247 Mon Sep 17 00:00:00 2001 From: Pekka J Enberg <penberg@cs.Helsinki.FI> Date: Fri, 9 Sep 2005 13:10:19 -0700 Subject: [PATCH 261/563] [PATCH] VFS: update documentation This patch brings the now out-of-date Documentation/filesystems/vfs.txt back to life. Thanks to Carsten Otte, Trond Myklebust, and Anton Altaparmakov for their help on updating this documentation. Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/filesystems/vfs.txt | 435 ++++++++++++++++++++++-------- 1 file changed, 323 insertions(+), 112 deletions(-) diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 3f318dd44c775..f042c12e0ed2d 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -1,35 +1,27 @@ -/* -*- auto-fill -*- */ - Overview of the Virtual File System + Overview of the Linux Virtual File System - Richard Gooch <rgooch@atnf.csiro.au> + Original author: Richard Gooch <rgooch@atnf.csiro.au> - 5-JUL-1999 + Last updated on August 25, 2005 + Copyright (C) 1999 Richard Gooch + Copyright (C) 2005 Pekka Enberg -Conventions used in this document <section> -================================= + This file is released under the GPLv2. -Each section in this document will have the string "<section>" at the -right-hand side of the section title. Each subsection will have -"<subsection>" at the right-hand side. These strings are meant to make -it easier to search through the document. -NOTE that the master copy of this document is available online at: -http://www.atnf.csiro.au/~rgooch/linux/docs/vfs.txt - - -What is it? <section> +What is it? =========== The Virtual File System (otherwise known as the Virtual Filesystem Switch) is the software layer in the kernel that provides the filesystem interface to userspace programs. It also provides an abstraction within the kernel which allows different filesystem -implementations to co-exist. +implementations to coexist. -A Quick Look At How It Works <section> +A Quick Look At How It Works ============================ In this section I'll briefly describe how things work, before @@ -38,7 +30,8 @@ when user programs open and manipulate files, and then look from the other view which is how a filesystem is supported and subsequently mounted. -Opening a File <subsection> + +Opening a File -------------- The VFS implements the open(2), stat(2), chmod(2) and similar system @@ -77,7 +70,7 @@ back to userspace. Opening a file requires another operation: allocation of a file structure (this is the kernel-side implementation of file -descriptors). The freshly allocated file structure is initialised with +descriptors). The freshly allocated file structure is initialized with a pointer to the dentry and a set of file operation member functions. These are taken from the inode data. The open() file method is then called so the specific filesystem implementation can do it's work. You @@ -102,7 +95,8 @@ filesystem or driver code at the same time, on different processors. You should ensure that access to shared resources is protected by appropriate locks. -Registering and Mounting a Filesystem <subsection> + +Registering and Mounting a Filesystem ------------------------------------- If you want to support a new kind of filesystem in the kernel, all you @@ -123,17 +117,21 @@ updated to point to the root inode for the new filesystem. It's now time to look at things in more detail. -struct file_system_type <section> +struct file_system_type ======================= -This describes the filesystem. As of kernel 2.1.99, the following +This describes the filesystem. As of kernel 2.6.13, the following members are defined: struct file_system_type { const char *name; int fs_flags; - struct super_block *(*read_super) (struct super_block *, void *, int); - struct file_system_type * next; + struct super_block *(*get_sb) (struct file_system_type *, int, + const char *, void *); + void (*kill_sb) (struct super_block *); + struct module *owner; + struct file_system_type * next; + struct list_head fs_supers; }; name: the name of the filesystem type, such as "ext2", "iso9660", @@ -141,51 +139,97 @@ struct file_system_type { fs_flags: various flags (i.e. FS_REQUIRES_DEV, FS_NO_DCACHE, etc.) - read_super: the method to call when a new instance of this + get_sb: the method to call when a new instance of this filesystem should be mounted - next: for internal VFS use: you should initialise this to NULL + kill_sb: the method to call when an instance of this filesystem + should be unmounted + + owner: for internal VFS use: you should initialize this to THIS_MODULE in + most cases. -The read_super() method has the following arguments: + next: for internal VFS use: you should initialize this to NULL + +The get_sb() method has the following arguments: struct super_block *sb: the superblock structure. This is partially - initialised by the VFS and the rest must be initialised by the - read_super() method + initialized by the VFS and the rest must be initialized by the + get_sb() method + + int flags: mount flags + + const char *dev_name: the device name we are mounting. void *data: arbitrary mount options, usually comes as an ASCII string int silent: whether or not to be silent on error -The read_super() method must determine if the block device specified +The get_sb() method must determine if the block device specified in the superblock contains a filesystem of the type the method supports. On success the method returns the superblock pointer, on failure it returns NULL. The most interesting member of the superblock structure that the -read_super() method fills in is the "s_op" field. This is a pointer to +get_sb() method fills in is the "s_op" field. This is a pointer to a "struct super_operations" which describes the next level of the filesystem implementation. +Usually, a filesystem uses generic one of the generic get_sb() +implementations and provides a fill_super() method instead. The +generic methods are: + + get_sb_bdev: mount a filesystem residing on a block device -struct super_operations <section> + get_sb_nodev: mount a filesystem that is not backed by a device + + get_sb_single: mount a filesystem which shares the instance between + all mounts + +A fill_super() method implementation has the following arguments: + + struct super_block *sb: the superblock structure. The method fill_super() + must initialize this properly. + + void *data: arbitrary mount options, usually comes as an ASCII + string + + int silent: whether or not to be silent on error + + +struct super_operations ======================= This describes how the VFS can manipulate the superblock of your -filesystem. As of kernel 2.1.99, the following members are defined: +filesystem. As of kernel 2.6.13, the following members are defined: struct super_operations { - void (*read_inode) (struct inode *); - int (*write_inode) (struct inode *, int); - void (*put_inode) (struct inode *); - void (*drop_inode) (struct inode *); - void (*delete_inode) (struct inode *); - int (*notify_change) (struct dentry *, struct iattr *); - void (*put_super) (struct super_block *); - void (*write_super) (struct super_block *); - int (*statfs) (struct super_block *, struct statfs *, int); - int (*remount_fs) (struct super_block *, int *, char *); - void (*clear_inode) (struct inode *); + struct inode *(*alloc_inode)(struct super_block *sb); + void (*destroy_inode)(struct inode *); + + void (*read_inode) (struct inode *); + + void (*dirty_inode) (struct inode *); + int (*write_inode) (struct inode *, int); + void (*put_inode) (struct inode *); + void (*drop_inode) (struct inode *); + void (*delete_inode) (struct inode *); + void (*put_super) (struct super_block *); + void (*write_super) (struct super_block *); + int (*sync_fs)(struct super_block *sb, int wait); + void (*write_super_lockfs) (struct super_block *); + void (*unlockfs) (struct super_block *); + int (*statfs) (struct super_block *, struct kstatfs *); + int (*remount_fs) (struct super_block *, int *, char *); + void (*clear_inode) (struct inode *); + void (*umount_begin) (struct super_block *); + + void (*sync_inodes) (struct super_block *sb, + struct writeback_control *wbc); + int (*show_options)(struct seq_file *, struct vfsmount *); + + ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); + ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); }; All methods are called without any locks being held, unless otherwise @@ -193,43 +237,62 @@ noted. This means that most methods can block safely. All methods are only called from a process context (i.e. not from an interrupt handler or bottom half). + alloc_inode: this method is called by inode_alloc() to allocate memory + for struct inode and initialize it. + + destroy_inode: this method is called by destroy_inode() to release + resources allocated for struct inode. + read_inode: this method is called to read a specific inode from the - mounted filesystem. The "i_ino" member in the "struct inode" - will be initialised by the VFS to indicate which inode to - read. Other members are filled in by this method + mounted filesystem. The i_ino member in the struct inode is + initialized by the VFS to indicate which inode to read. Other + members are filled in by this method. + + You can set this to NULL and use iget5_locked() instead of iget() + to read inodes. This is necessary for filesystems for which the + inode number is not sufficient to identify an inode. + + dirty_inode: this method is called by the VFS to mark an inode dirty. write_inode: this method is called when the VFS needs to write an inode to disc. The second parameter indicates whether the write should be synchronous or not, not all filesystems check this flag. put_inode: called when the VFS inode is removed from the inode - cache. This method is optional + cache. drop_inode: called when the last access to the inode is dropped, with the inode_lock spinlock held. - This method should be either NULL (normal unix filesystem + This method should be either NULL (normal UNIX filesystem semantics) or "generic_delete_inode" (for filesystems that do not want to cache inodes - causing "delete_inode" to always be called regardless of the value of i_nlink) - The "generic_delete_inode()" behaviour is equivalent to the + The "generic_delete_inode()" behavior is equivalent to the old practice of using "force_delete" in the put_inode() case, but does not have the races that the "force_delete()" approach had. delete_inode: called when the VFS wants to delete an inode - notify_change: called when VFS inode attributes are changed. If this - is NULL the VFS falls back to the write_inode() method. This - is called with the kernel lock held - put_super: called when the VFS wishes to free the superblock (i.e. unmount). This is called with the superblock lock held write_super: called when the VFS superblock needs to be written to disc. This method is optional + sync_fs: called when VFS is writing out all dirty data associated with + a superblock. The second parameter indicates whether the method + should wait until the write out has been completed. Optional. + + write_super_lockfs: called when VFS is locking a filesystem and forcing + it into a consistent state. This function is currently used by the + Logical Volume Manager (LVM). + + unlockfs: called when VFS is unlocking a filesystem and making it writable + again. + statfs: called when the VFS needs to get filesystem statistics. This is called with the kernel lock held @@ -238,21 +301,31 @@ or bottom half). clear_inode: called then the VFS clears the inode. Optional + umount_begin: called when the VFS is unmounting a filesystem. + + sync_inodes: called when the VFS is writing out dirty data associated with + a superblock. + + show_options: called by the VFS to show mount options for /proc/<pid>/mounts. + + quota_read: called by the VFS to read from filesystem quota file. + + quota_write: called by the VFS to write to filesystem quota file. + The read_inode() method is responsible for filling in the "i_op" field. This is a pointer to a "struct inode_operations" which describes the methods that can be performed on individual inodes. -struct inode_operations <section> +struct inode_operations ======================= This describes how the VFS can manipulate an inode in your -filesystem. As of kernel 2.1.99, the following members are defined: +filesystem. As of kernel 2.6.13, the following members are defined: struct inode_operations { - struct file_operations * default_file_ops; - int (*create) (struct inode *,struct dentry *,int); - int (*lookup) (struct inode *,struct dentry *); + int (*create) (struct inode *,struct dentry *,int, struct nameidata *); + struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); int (*link) (struct dentry *,struct inode *,struct dentry *); int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct inode *,struct dentry *,const char *); @@ -261,25 +334,22 @@ struct inode_operations { int (*mknod) (struct inode *,struct dentry *,int,dev_t); int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *); - int (*readlink) (struct dentry *, char *,int); - struct dentry * (*follow_link) (struct dentry *, struct dentry *); - int (*readpage) (struct file *, struct page *); - int (*writepage) (struct page *page, struct writeback_control *wbc); - int (*bmap) (struct inode *,int); + int (*readlink) (struct dentry *, char __user *,int); + void * (*follow_link) (struct dentry *, struct nameidata *); + void (*put_link) (struct dentry *, struct nameidata *, void *); void (*truncate) (struct inode *); - int (*permission) (struct inode *, int); - int (*smap) (struct inode *,int); - int (*updatepage) (struct file *, struct page *, const char *, - unsigned long, unsigned int, int); - int (*revalidate) (struct dentry *); + int (*permission) (struct inode *, int, struct nameidata *); + int (*setattr) (struct dentry *, struct iattr *); + int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); + int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); + ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); + ssize_t (*listxattr) (struct dentry *, char *, size_t); + int (*removexattr) (struct dentry *, const char *); }; Again, all methods are called without any locks being held, unless otherwise noted. - default_file_ops: this is a pointer to a "struct file_operations" - which describes how to open and then manipulate open files - create: called by the open(2) and creat(2) system calls. Only required if you want to support regular files. The dentry you get should not have an inode (i.e. it should be a negative @@ -328,31 +398,143 @@ otherwise noted. you want to support reading symbolic links follow_link: called by the VFS to follow a symbolic link to the - inode it points to. Only required if you want to support - symbolic links + inode it points to. Only required if you want to support + symbolic links. This function returns a void pointer cookie + that is passed to put_link(). + + put_link: called by the VFS to release resources allocated by + follow_link(). The cookie returned by follow_link() is passed to + to this function as the last parameter. It is used by filesystems + such as NFS where page cache is not stable (i.e. page that was + installed when the symbolic link walk started might not be in the + page cache at the end of the walk). + + truncate: called by the VFS to change the size of a file. The i_size + field of the inode is set to the desired size by the VFS before + this function is called. This function is called by the truncate(2) + system call and related functionality. + + permission: called by the VFS to check for access rights on a POSIX-like + filesystem. + + setattr: called by the VFS to set attributes for a file. This function is + called by chmod(2) and related system calls. + + getattr: called by the VFS to get attributes of a file. This function is + called by stat(2) and related system calls. + + setxattr: called by the VFS to set an extended attribute for a file. + Extended attribute is a name:value pair associated with an inode. This + function is called by setxattr(2) system call. + + getxattr: called by the VFS to retrieve the value of an extended attribute + name. This function is called by getxattr(2) function call. + + listxattr: called by the VFS to list all extended attributes for a given + file. This function is called by listxattr(2) system call. + + removexattr: called by the VFS to remove an extended attribute from a file. + This function is called by removexattr(2) system call. + + +struct address_space_operations +=============================== + +This describes how the VFS can manipulate mapping of a file to page cache in +your filesystem. As of kernel 2.6.13, the following members are defined: + +struct address_space_operations { + int (*writepage)(struct page *page, struct writeback_control *wbc); + int (*readpage)(struct file *, struct page *); + int (*sync_page)(struct page *); + int (*writepages)(struct address_space *, struct writeback_control *); + int (*set_page_dirty)(struct page *page); + int (*readpages)(struct file *filp, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages); + int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); + int (*commit_write)(struct file *, struct page *, unsigned, unsigned); + sector_t (*bmap)(struct address_space *, sector_t); + int (*invalidatepage) (struct page *, unsigned long); + int (*releasepage) (struct page *, int); + ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov, + loff_t offset, unsigned long nr_segs); + struct page* (*get_xip_page)(struct address_space *, sector_t, + int); +}; + + writepage: called by the VM write a dirty page to backing store. + + readpage: called by the VM to read a page from backing store. + + sync_page: called by the VM to notify the backing store to perform all + queued I/O operations for a page. I/O operations for other pages + associated with this address_space object may also be performed. + + writepages: called by the VM to write out pages associated with the + address_space object. + + set_page_dirty: called by the VM to set a page dirty. + + readpages: called by the VM to read pages associated with the address_space + object. + prepare_write: called by the generic write path in VM to set up a write + request for a page. -struct file_operations <section> + commit_write: called by the generic write path in VM to write page to + its backing store. + + bmap: called by the VFS to map a logical block offset within object to + physical block number. This method is use by for the legacy FIBMAP + ioctl. Other uses are discouraged. + + invalidatepage: called by the VM on truncate to disassociate a page from its + address_space mapping. + + releasepage: called by the VFS to release filesystem specific metadata from + a page. + + direct_IO: called by the VM for direct I/O writes and reads. + + get_xip_page: called by the VM to translate a block number to a page. + The page is valid until the corresponding filesystem is unmounted. + Filesystems that want to use execute-in-place (XIP) need to implement + it. An example implementation can be found in fs/ext2/xip.c. + + +struct file_operations ====================== This describes how the VFS can manipulate an open file. As of kernel -2.1.99, the following members are defined: +2.6.13, the following members are defined: struct file_operations { loff_t (*llseek) (struct file *, loff_t, int); - ssize_t (*read) (struct file *, char *, size_t, loff_t *); - ssize_t (*write) (struct file *, const char *, size_t, loff_t *); + ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); + ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t); + ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); + ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); + long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); + long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); + int (*flush) (struct file *); int (*release) (struct inode *, struct file *); - int (*fsync) (struct file *, struct dentry *); - int (*fasync) (struct file *, int); - int (*check_media_change) (kdev_t dev); - int (*revalidate) (kdev_t dev); + int (*fsync) (struct file *, struct dentry *, int datasync); + int (*aio_fsync) (struct kiocb *, int datasync); + int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); + ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); + ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); + ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); + ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); + unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + int (*check_flags)(int); + int (*dir_notify)(struct file *filp, unsigned long arg); + int (*flock) (struct file *, int, struct file_lock *); }; Again, all methods are called without any locks being held, unless @@ -362,8 +544,12 @@ otherwise noted. read: called by read(2) and related system calls + aio_read: called by io_submit(2) and other asynchronous I/O operations + write: called by write(2) and related system calls + aio_write: called by io_submit(2) and other asynchronous I/O operations + readdir: called when the VFS needs to read the directory contents poll: called by the VFS when a process wants to check if there is @@ -372,18 +558,25 @@ otherwise noted. ioctl: called by the ioctl(2) system call + unlocked_ioctl: called by the ioctl(2) system call. Filesystems that do not + require the BKL should use this method instead of the ioctl() above. + + compat_ioctl: called by the ioctl(2) system call when 32 bit system calls + are used on 64 bit kernels. + mmap: called by the mmap(2) system call open: called by the VFS when an inode should be opened. When the VFS - opens a file, it creates a new "struct file" and initialises - the "f_op" file operations member with the "default_file_ops" - field in the inode structure. It then calls the open method - for the newly allocated file structure. You might think that - the open method really belongs in "struct inode_operations", - and you may be right. I think it's done the way it is because - it makes filesystems simpler to implement. The open() method - is a good place to initialise the "private_data" member in the - file structure if you want to point to a device structure + opens a file, it creates a new "struct file". It then calls the + open method for the newly allocated file structure. You might + think that the open method really belongs in + "struct inode_operations", and you may be right. I think it's + done the way it is because it makes filesystems simpler to + implement. The open() method is a good place to initialize the + "private_data" member in the file structure if you want to point + to a device structure + + flush: called by the close(2) system call to flush a file release: called when the last reference to an open file is closed @@ -392,6 +585,23 @@ otherwise noted. fasync: called by the fcntl(2) system call when asynchronous (non-blocking) mode is enabled for a file + lock: called by the fcntl(2) system call for F_GETLK, F_SETLK, and F_SETLKW + commands + + readv: called by the readv(2) system call + + writev: called by the writev(2) system call + + sendfile: called by the sendfile(2) system call + + get_unmapped_area: called by the mmap(2) system call + + check_flags: called by the fcntl(2) system call for F_SETFL command + + dir_notify: called by the fcntl(2) system call for F_NOTIFY command + + flock: called by the flock(2) system call + Note that the file operations are implemented by the specific filesystem in which the inode resides. When opening a device node (character or block special) most filesystems will call special @@ -400,29 +610,28 @@ driver information. These support routines replace the filesystem file operations with those for the device driver, and then proceed to call the new open() method for the file. This is how opening a device file in the filesystem eventually ends up calling the device driver open() -method. Note the devfs (the Device FileSystem) has a more direct path -from device node to device driver (this is an unofficial kernel -patch). +method. -Directory Entry Cache (dcache) <section> ------------------------------- +Directory Entry Cache (dcache) +============================== + struct dentry_operations -======================== +------------------------ This describes how a filesystem can overload the standard dentry operations. Dentries and the dcache are the domain of the VFS and the individual filesystem implementations. Device drivers have no business here. These methods may be set to NULL, as they are either optional or -the VFS uses a default. As of kernel 2.1.99, the following members are +the VFS uses a default. As of kernel 2.6.13, the following members are defined: struct dentry_operations { - int (*d_revalidate)(struct dentry *); + int (*d_revalidate)(struct dentry *, struct nameidata *); int (*d_hash) (struct dentry *, struct qstr *); int (*d_compare) (struct dentry *, struct qstr *, struct qstr *); - void (*d_delete)(struct dentry *); + int (*d_delete)(struct dentry *); void (*d_release)(struct dentry *); void (*d_iput)(struct dentry *, struct inode *); }; @@ -451,6 +660,7 @@ Each dentry has a pointer to its parent dentry, as well as a hash list of child dentries. Child dentries are basically like files in a directory. + Directory Entry Cache APIs -------------------------- @@ -471,7 +681,7 @@ manipulate dentries: "d_delete" method is called d_drop: this unhashes a dentry from its parents hash list. A - subsequent call to dput() will dellocate the dentry if its + subsequent call to dput() will deallocate the dentry if its usage count drops to 0 d_delete: delete a dentry. If there are no other open references to @@ -507,16 +717,16 @@ up by walking the tree starting with the first component of the pathname and using that dentry along with the next component to look up the next level and so on. Since it is a frequent operation for workloads like multiuser -environments and webservers, it is important to optimize +environments and web servers, it is important to optimize this path. Prior to 2.5.10, dcache_lock was acquired in d_lookup and thus in every component during path look-up. Since 2.5.10 onwards, -fastwalk algorithm changed this by holding the dcache_lock +fast-walk algorithm changed this by holding the dcache_lock at the beginning and walking as many cached path component -dentries as possible. This signficantly decreases the number +dentries as possible. This significantly decreases the number of acquisition of dcache_lock. However it also increases the -lock hold time signficantly and affects performance in large +lock hold time significantly and affects performance in large SMP machines. Since 2.5.62 kernel, dcache has been using a new locking model that uses RCU to make dcache look-up lock-free. @@ -527,7 +737,7 @@ protected the hash chain, d_child, d_alias, d_lru lists as well as d_inode and several other things like mount look-up. RCU-based changes affect only the way the hash chain is protected. For everything else the dcache_lock must be taken for both traversing as well as -updating. The hash chain updations too take the dcache_lock. +updating. The hash chain updates too take the dcache_lock. The significant change is the way d_lookup traverses the hash chain, it doesn't acquire the dcache_lock for this and rely on RCU to ensure that the dentry has not been *freed*. @@ -535,14 +745,15 @@ ensure that the dentry has not been *freed*. Dcache locking details ---------------------- + For many multi-user workloads, open() and stat() on files are very frequently occurring operations. Both involve walking of path names to find the dentry corresponding to the concerned file. In 2.4 kernel, dcache_lock was held during look-up of each path component. Contention and -cacheline bouncing of this global lock caused significant +cache-line bouncing of this global lock caused significant scalability problems. With the introduction of RCU -in linux kernel, this was worked around by making +in Linux kernel, this was worked around by making the look-up of path components during path walking lock-free. @@ -562,7 +773,7 @@ Some of the important changes are : 2. Insertion of a dentry into the hash table is done using hlist_add_head_rcu() which take care of ordering the writes - the writes to the dentry must be visible before the dentry - is inserted. This works in conjuction with hlist_for_each_rcu() + is inserted. This works in conjunction with hlist_for_each_rcu() while walking the hash chain. The only requirement is that all initialization to the dentry must be done before hlist_add_head_rcu() since we don't have dcache_lock protection while traversing @@ -584,7 +795,7 @@ Some of the important changes are : the same. In some sense, dcache_rcu path walking looks like the pre-2.5.10 version. -5. All dentry hash chain updations must take the dcache_lock as well as +5. All dentry hash chain updates must take the dcache_lock as well as the per-dentry lock in that order. dput() does this to ensure that a dentry that has just been looked up in another CPU doesn't get deleted before dget() can be done on it. @@ -640,10 +851,10 @@ handled as described below : Since we redo the d_parent check and compare name while holding d_lock, lock-free look-up will not race against d_move(). -4. There can be a theoritical race when a dentry keeps coming back +4. There can be a theoretical race when a dentry keeps coming back to original bucket due to double moves. Due to this look-up may consider that it has never moved and can end up in a infinite loop. - But this is not any worse that theoritical livelocks we already + But this is not any worse that theoretical livelocks we already have in the kernel. -- GitLab From e272d50688a1cae66a12426da128483197843d9f Mon Sep 17 00:00:00 2001 From: Ben Dooks <ben-lkinux@fluff.org> Date: Fri, 9 Sep 2005 13:10:20 -0700 Subject: [PATCH 262/563] [PATCH] Documentation/sparse snapshot URL The URL for Documentation/sparse is wrong now that it is in git. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/sparse.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sparse.txt b/Documentation/sparse.txt index f978414784590..5df44dc894e59 100644 --- a/Documentation/sparse.txt +++ b/Documentation/sparse.txt @@ -57,7 +57,7 @@ With BK, you can just get it from and DaveJ has tar-balls at - http://www.codemonkey.org.uk/projects/bitkeeper/sparse/ + http://www.codemonkey.org.uk/projects/git-snapshots/sparse/ Once you have it, just do -- GitLab From 04578f174f43d29b569500f01ba772afa4016330 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:22 -0700 Subject: [PATCH 263/563] [PATCH] FUSE - MAINTAINERS, Kconfig and Makefile changes This patch adds FUSE filesystem to MAINTAINERS, fs/Kconfig and fs/Makefile. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- MAINTAINERS | 7 +++++++ fs/Kconfig | 13 +++++++++++++ fs/Makefile | 1 + 3 files changed, 21 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9c9a86d0685a5..f038dca34ee82 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -931,6 +931,13 @@ L: linux-tape@vger.kernel.org W: http://sourceforge.net/projects/ftape S: Orphan +FUSE: FILESYSTEM IN USERSPACE +P: Miklos Szeredi +M: miklos@szeredi.hu +L: fuse-devel@lists.sourceforge.net +W: http://fuse.sourceforge.net/ +S: Maintained + FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit) P: Rik Faith M: faith@cs.unc.edu diff --git a/fs/Kconfig b/fs/Kconfig index 443aed4e20671..068ccea2f184b 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -462,6 +462,19 @@ config AUTOFS4_FS local network, you probably do not need an automounter, and can say N here. +config FUSE_FS + tristate "Filesystem in Userspace support" + help + With FUSE it is possible to implement a fully functional filesystem + in a userspace program. + + There's also companion library: libfuse. This library along with + utilities is available from the FUSE homepage: + <http://fuse.sourceforge.net/> + + If you want to develop a userspace FS, or if you want to use + a filesystem based on FUSE, answer Y or M. + menu "CD-ROM/DVD Filesystems" config ISO9660_FS diff --git a/fs/Makefile b/fs/Makefile index d646502c1efb3..1972da1862729 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_QNX4FS_FS) += qnx4/ obj-$(CONFIG_AUTOFS_FS) += autofs/ obj-$(CONFIG_AUTOFS4_FS) += autofs4/ obj-$(CONFIG_ADFS_FS) += adfs/ +obj-$(CONFIG_FUSE_FS) += fuse/ obj-$(CONFIG_UDF_FS) += udf/ obj-$(CONFIG_RELAYFS_FS) += relayfs/ obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ -- GitLab From d8a5ba45457e4a22aa39c939121efd7bb6c76672 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:26 -0700 Subject: [PATCH 264/563] [PATCH] FUSE - core This patch adds FUSE core. This contains the following files: o inode.c - superblock operations (alloc_inode, destroy_inode, read_inode, clear_inode, put_super, show_options) - registers FUSE filesystem o fuse_i.h - private header file Requirements ============ The most important difference between orinary filesystems and FUSE is the fact, that the filesystem data/metadata is provided by a userspace process run with the privileges of the mount "owner" instead of the kernel, or some remote entity usually running with elevated privileges. The security implication of this is that a non-privileged user must not be able to use this capability to compromise the system. Obvious requirements arising from this are: - mount owner should not be able to get elevated privileges with the help of the mounted filesystem - mount owner should not be able to induce undesired behavior in other users' or the super user's processes - mount owner should not get illegitimate access to information from other users' and the super user's processes These are currently ensured with the following constraints: 1) mount is only allowed to directory or file which the mount owner can modify without limitation (write access + no sticky bit for directories) 2) nosuid,nodev mount options are forced 3) any process running with fsuid different from the owner is denied all access to the filesystem 1) and 2) are ensured by the "fusermount" mount utility which is a setuid root application doing the actual mount operation. 3) is ensured by a check in the permission() method in kernel I started thinking about doing 3) in a different way because Christoph H. made a big deal out of it, saying that FUSE is unacceptable into mainline in this form. The suggested use of private namespaces would be OK, but in their current form have many limitations that make their use impractical (as discussed in this thread). Suggested improvements that would address these limitations: - implement shared subtrees - allow a process to join an existing namespace (make namespaces first-class objects) - implement the namespace creation/joining in a PAM module With all that in place the check of owner against current->fsuid may be removed from the FUSE kernel module, without compromising the security requirements. Suid programs still interesting questions, since they get access even to the private namespace causing some information leak (exact order/timing of filesystem operations performed), giving some ptrace-like capabilities to unprivileged users. BTW this problem is not strictly limited to the namespace approach, since suid programs setting fsuid and accessing users' files will succeed with the current approach too. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/Makefile | 7 + fs/fuse/fuse_i.h | 89 +++++++++ fs/fuse/inode.c | 428 +++++++++++++++++++++++++++++++++++++++++++ include/linux/fuse.h | 38 ++++ 4 files changed, 562 insertions(+) create mode 100644 fs/fuse/Makefile create mode 100644 fs/fuse/fuse_i.h create mode 100644 fs/fuse/inode.c create mode 100644 include/linux/fuse.h diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile new file mode 100644 index 0000000000000..9c3e4cc7b1a63 --- /dev/null +++ b/fs/fuse/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the FUSE filesystem. +# + +obj-$(CONFIG_FUSE_FS) += fuse.o + +fuse-objs := inode.o diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h new file mode 100644 index 0000000000000..eed6e89ce01f7 --- /dev/null +++ b/fs/fuse/fuse_i.h @@ -0,0 +1,89 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include <linux/fuse.h> +#include <linux/fs.h> +#include <linux/wait.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/backing-dev.h> +#include <asm/semaphore.h> + +/** FUSE inode */ +struct fuse_inode { + /** Inode data */ + struct inode inode; + + /** Unique ID, which identifies the inode between userspace + * and kernel */ + u64 nodeid; + + /** Time in jiffies until the file attributes are valid */ + unsigned long i_time; +}; + +/** + * A Fuse connection. + * + * This structure is created, when the filesystem is mounted, and is + * destroyed, when the client device is closed and the filesystem is + * unmounted. + */ +struct fuse_conn { + /** The superblock of the mounted filesystem */ + struct super_block *sb; + + /** The user id for this mount */ + uid_t user_id; + + /** Backing dev info */ + struct backing_dev_info bdi; +}; + +static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb) +{ + return (struct fuse_conn **) &sb->s_fs_info; +} + +static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) +{ + return *get_fuse_conn_super_p(sb); +} + +static inline struct fuse_conn *get_fuse_conn(struct inode *inode) +{ + return get_fuse_conn_super(inode->i_sb); +} + +static inline struct fuse_inode *get_fuse_inode(struct inode *inode) +{ + return container_of(inode, struct fuse_inode, inode); +} + +static inline u64 get_node_id(struct inode *inode) +{ + return get_fuse_inode(inode)->nodeid; +} + +/** + * This is the single global spinlock which protects FUSE's structures + * + * The following data is protected by this lock: + * + * - the s_fs_info field of the super block + * - the sb (super_block) field in fuse_conn + */ +extern spinlock_t fuse_lock; + +/** + * Check if the connection can be released, and if yes, then free the + * connection structure + */ +void fuse_release_conn(struct fuse_conn *fc); + diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c new file mode 100644 index 0000000000000..ea6339c2b6a1b --- /dev/null +++ b/fs/fuse/inode.c @@ -0,0 +1,428 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include "fuse_i.h" + +#include <linux/pagemap.h> +#include <linux/slab.h> +#include <linux/file.h> +#include <linux/mount.h> +#include <linux/seq_file.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/parser.h> +#include <linux/statfs.h> + +MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); +MODULE_DESCRIPTION("Filesystem in Userspace"); +MODULE_LICENSE("GPL"); + +spinlock_t fuse_lock; +static kmem_cache_t *fuse_inode_cachep; +static int mount_count; + +static int mount_max = 1000; +module_param(mount_max, int, 0644); +MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)"); + +#define FUSE_SUPER_MAGIC 0x65735546 + +struct fuse_mount_data { + int fd; + unsigned rootmode; + unsigned user_id; +}; + +static struct inode *fuse_alloc_inode(struct super_block *sb) +{ + struct inode *inode; + struct fuse_inode *fi; + + inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL); + if (!inode) + return NULL; + + fi = get_fuse_inode(inode); + fi->i_time = jiffies - 1; + fi->nodeid = 0; + + return inode; +} + +static void fuse_destroy_inode(struct inode *inode) +{ + kmem_cache_free(fuse_inode_cachep, inode); +} + +static void fuse_read_inode(struct inode *inode) +{ + /* No op */ +} + +static void fuse_clear_inode(struct inode *inode) +{ +} + +void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) +{ + if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) + invalidate_inode_pages(inode->i_mapping); + + inode->i_ino = attr->ino; + inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777); + inode->i_nlink = attr->nlink; + inode->i_uid = attr->uid; + inode->i_gid = attr->gid; + i_size_write(inode, attr->size); + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = attr->blocks; + inode->i_atime.tv_sec = attr->atime; + inode->i_atime.tv_nsec = attr->atimensec; + inode->i_mtime.tv_sec = attr->mtime; + inode->i_mtime.tv_nsec = attr->mtimensec; + inode->i_ctime.tv_sec = attr->ctime; + inode->i_ctime.tv_nsec = attr->ctimensec; +} + +static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) +{ + inode->i_mode = attr->mode & S_IFMT; + i_size_write(inode, attr->size); +} + +static int fuse_inode_eq(struct inode *inode, void *_nodeidp) +{ + unsigned long nodeid = *(unsigned long *) _nodeidp; + if (get_node_id(inode) == nodeid) + return 1; + else + return 0; +} + +static int fuse_inode_set(struct inode *inode, void *_nodeidp) +{ + unsigned long nodeid = *(unsigned long *) _nodeidp; + get_fuse_inode(inode)->nodeid = nodeid; + return 0; +} + +struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, + int generation, struct fuse_attr *attr, int version) +{ + struct inode *inode; + struct fuse_conn *fc = get_fuse_conn_super(sb); + int retried = 0; + + retry: + inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); + if (!inode) + return NULL; + + if ((inode->i_state & I_NEW)) { + inode->i_generation = generation; + inode->i_data.backing_dev_info = &fc->bdi; + fuse_init_inode(inode, attr); + unlock_new_inode(inode); + } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { + BUG_ON(retried); + /* Inode has changed type, any I/O on the old should fail */ + make_bad_inode(inode); + iput(inode); + retried = 1; + goto retry; + } + + fuse_change_attributes(inode, attr); + inode->i_version = version; + return inode; +} + +static void fuse_put_super(struct super_block *sb) +{ + struct fuse_conn *fc = get_fuse_conn_super(sb); + + spin_lock(&fuse_lock); + mount_count --; + fc->sb = NULL; + fc->user_id = 0; + fuse_release_conn(fc); + *get_fuse_conn_super_p(sb) = NULL; + spin_unlock(&fuse_lock); +} + +enum { + OPT_FD, + OPT_ROOTMODE, + OPT_USER_ID, + OPT_DEFAULT_PERMISSIONS, + OPT_ALLOW_OTHER, + OPT_ALLOW_ROOT, + OPT_KERNEL_CACHE, + OPT_ERR +}; + +static match_table_t tokens = { + {OPT_FD, "fd=%u"}, + {OPT_ROOTMODE, "rootmode=%o"}, + {OPT_USER_ID, "user_id=%u"}, + {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, + {OPT_ALLOW_OTHER, "allow_other"}, + {OPT_ALLOW_ROOT, "allow_root"}, + {OPT_KERNEL_CACHE, "kernel_cache"}, + {OPT_ERR, NULL} +}; + +static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) +{ + char *p; + memset(d, 0, sizeof(struct fuse_mount_data)); + d->fd = -1; + + while ((p = strsep(&opt, ",")) != NULL) { + int token; + int value; + substring_t args[MAX_OPT_ARGS]; + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case OPT_FD: + if (match_int(&args[0], &value)) + return 0; + d->fd = value; + break; + + case OPT_ROOTMODE: + if (match_octal(&args[0], &value)) + return 0; + d->rootmode = value; + break; + + case OPT_USER_ID: + if (match_int(&args[0], &value)) + return 0; + d->user_id = value; + break; + + default: + return 0; + } + } + if (d->fd == -1) + return 0; + + return 1; +} + +static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); + + seq_printf(m, ",user_id=%u", fc->user_id); + return 0; +} + +void fuse_release_conn(struct fuse_conn *fc) +{ + kfree(fc); +} + +static struct fuse_conn *new_conn(void) +{ + struct fuse_conn *fc; + + fc = kmalloc(sizeof(*fc), GFP_KERNEL); + if (fc != NULL) { + memset(fc, 0, sizeof(*fc)); + fc->sb = NULL; + fc->user_id = 0; + fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; + fc->bdi.unplug_io_fn = default_unplug_io_fn; + } + return fc; +} + +static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) +{ + struct fuse_conn *fc; + + fc = new_conn(); + if (fc == NULL) + return NULL; + spin_lock(&fuse_lock); + fc->sb = sb; + spin_unlock(&fuse_lock); + return fc; +} + +static struct inode *get_root_inode(struct super_block *sb, unsigned mode) +{ + struct fuse_attr attr; + memset(&attr, 0, sizeof(attr)); + + attr.mode = mode; + attr.ino = FUSE_ROOT_ID; + return fuse_iget(sb, 1, 0, &attr, 0); +} + +static struct super_operations fuse_super_operations = { + .alloc_inode = fuse_alloc_inode, + .destroy_inode = fuse_destroy_inode, + .read_inode = fuse_read_inode, + .clear_inode = fuse_clear_inode, + .put_super = fuse_put_super, + .show_options = fuse_show_options, +}; + +static int inc_mount_count(void) +{ + int success = 0; + spin_lock(&fuse_lock); + mount_count ++; + if (mount_max == -1 || mount_count <= mount_max) + success = 1; + spin_unlock(&fuse_lock); + return success; +} + +static int fuse_fill_super(struct super_block *sb, void *data, int silent) +{ + struct fuse_conn *fc; + struct inode *root; + struct fuse_mount_data d; + struct file *file; + int err; + + if (!parse_fuse_opt((char *) data, &d)) + return -EINVAL; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = FUSE_SUPER_MAGIC; + sb->s_op = &fuse_super_operations; + sb->s_maxbytes = MAX_LFS_FILESIZE; + + file = fget(d.fd); + if (!file) + return -EINVAL; + + fc = get_conn(file, sb); + fput(file); + if (fc == NULL) + return -EINVAL; + + fc->user_id = d.user_id; + + *get_fuse_conn_super_p(sb) = fc; + + err = -ENFILE; + if (!inc_mount_count() && current->uid != 0) + goto err; + + err = -ENOMEM; + root = get_root_inode(sb, d.rootmode); + if (root == NULL) + goto err; + + sb->s_root = d_alloc_root(root); + if (!sb->s_root) { + iput(root); + goto err; + } + return 0; + + err: + spin_lock(&fuse_lock); + mount_count --; + fc->sb = NULL; + fuse_release_conn(fc); + spin_unlock(&fuse_lock); + *get_fuse_conn_super_p(sb) = NULL; + return err; +} + +static struct super_block *fuse_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *raw_data) +{ + return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super); +} + +static struct file_system_type fuse_fs_type = { + .owner = THIS_MODULE, + .name = "fuse", + .get_sb = fuse_get_sb, + .kill_sb = kill_anon_super, +}; + +static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, + unsigned long flags) +{ + struct inode * inode = foo; + + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) + inode_init_once(inode); +} + +static int __init fuse_fs_init(void) +{ + int err; + + err = register_filesystem(&fuse_fs_type); + if (err) + printk("fuse: failed to register filesystem\n"); + else { + fuse_inode_cachep = kmem_cache_create("fuse_inode", + sizeof(struct fuse_inode), + 0, SLAB_HWCACHE_ALIGN, + fuse_inode_init_once, NULL); + if (!fuse_inode_cachep) { + unregister_filesystem(&fuse_fs_type); + err = -ENOMEM; + } + } + + return err; +} + +static void fuse_fs_cleanup(void) +{ + unregister_filesystem(&fuse_fs_type); + kmem_cache_destroy(fuse_inode_cachep); +} + +static int __init fuse_init(void) +{ + int res; + + printk("fuse init (API version %i.%i)\n", + FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); + + spin_lock_init(&fuse_lock); + res = fuse_fs_init(); + if (res) + goto err; + + return 0; + + err: + return res; +} + +static void __exit fuse_exit(void) +{ + printk(KERN_DEBUG "fuse exit\n"); + + fuse_fs_cleanup(); +} + +module_init(fuse_init); +module_exit(fuse_exit); diff --git a/include/linux/fuse.h b/include/linux/fuse.h new file mode 100644 index 0000000000000..2b1f4ae01e9de --- /dev/null +++ b/include/linux/fuse.h @@ -0,0 +1,38 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +/* This file defines the kernel interface of FUSE */ + +#include <asm/types.h> + +/** Version number of this interface */ +#define FUSE_KERNEL_VERSION 5 + +/** Minor version number of this interface */ +#define FUSE_KERNEL_MINOR_VERSION 1 + +/** The node ID of the root inode */ +#define FUSE_ROOT_ID 1 + +struct fuse_attr { + __u64 ino; + __u64 size; + __u64 blocks; + __u64 atime; + __u64 mtime; + __u64 ctime; + __u32 atimensec; + __u32 mtimensec; + __u32 ctimensec; + __u32 mode; + __u32 nlink; + __u32 uid; + __u32 gid; + __u32 rdev; +}; + -- GitLab From 334f485df85ac7736ebe14940bf0a059c5f26d7d Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:27 -0700 Subject: [PATCH 265/563] [PATCH] FUSE - device functions This adds the FUSE device handling functions. This contains the following files: o dev.c - fuse device operations (read, write, release, poll) - registers misc device - support for sending requests to userspace Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/filesystems/fuse.txt | 341 +++++++++++ fs/fuse/Makefile | 2 +- fs/fuse/dev.c | 884 +++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 223 ++++++++ fs/fuse/inode.c | 58 +- include/linux/fuse.h | 36 +- 6 files changed, 1537 insertions(+), 7 deletions(-) create mode 100644 Documentation/filesystems/fuse.txt create mode 100644 fs/fuse/dev.c diff --git a/Documentation/filesystems/fuse.txt b/Documentation/filesystems/fuse.txt new file mode 100644 index 0000000000000..83f96cf569603 --- /dev/null +++ b/Documentation/filesystems/fuse.txt @@ -0,0 +1,341 @@ +Definitions +~~~~~~~~~~~ + +Userspace filesystem: + + A filesystem in which data and metadata are provided by an ordinary + userspace process. The filesystem can be accessed normally through + the kernel interface. + +Filesystem daemon: + + The process(es) providing the data and metadata of the filesystem. + +Non-privileged mount (or user mount): + + A userspace filesystem mounted by a non-privileged (non-root) user. + The filesystem daemon is running with the privileges of the mounting + user. NOTE: this is not the same as mounts allowed with the "user" + option in /etc/fstab, which is not discussed here. + +Mount owner: + + The user who does the mounting. + +User: + + The user who is performing filesystem operations. + +What is FUSE? +~~~~~~~~~~~~~ + +FUSE is a userspace filesystem framework. It consists of a kernel +module (fuse.ko), a userspace library (libfuse.*) and a mount utility +(fusermount). + +One of the most important features of FUSE is allowing secure, +non-privileged mounts. This opens up new possibilities for the use of +filesystems. A good example is sshfs: a secure network filesystem +using the sftp protocol. + +The userspace library and utilities are available from the FUSE +homepage: + + http://fuse.sourceforge.net/ + +Mount options +~~~~~~~~~~~~~ + +'fd=N' + + The file descriptor to use for communication between the userspace + filesystem and the kernel. The file descriptor must have been + obtained by opening the FUSE device ('/dev/fuse'). + +'rootmode=M' + + The file mode of the filesystem's root in octal representation. + +'user_id=N' + + The numeric user id of the mount owner. + +'group_id=N' + + The numeric group id of the mount owner. + +'default_permissions' + + By default FUSE doesn't check file access permissions, the + filesystem is free to implement it's access policy or leave it to + the underlying file access mechanism (e.g. in case of network + filesystems). This option enables permission checking, restricting + access based on file mode. This is option is usually useful + together with the 'allow_other' mount option. + +'allow_other' + + This option overrides the security measure restricting file access + to the user mounting the filesystem. This option is by default only + allowed to root, but this restriction can be removed with a + (userspace) configuration option. + +'kernel_cache' + + This option disables flushing the cache of the file contents on + every open(). This should only be enabled on filesystems, where the + file data is never changed externally (not through the mounted FUSE + filesystem). Thus it is not suitable for network filesystems and + other "intermediate" filesystems. + + NOTE: if this option is not specified (and neither 'direct_io') data + is still cached after the open(), so a read() system call will not + always initiate a read operation. + +'direct_io' + + This option disables the use of page cache (file content cache) in + the kernel for this filesystem. This has several affects: + + - Each read() or write() system call will initiate one or more + read or write operations, data will not be cached in the + kernel. + + - The return value of the read() and write() system calls will + correspond to the return values of the read and write + operations. This is useful for example if the file size is not + known in advance (before reading it). + +'max_read=N' + + With this option the maximum size of read operations can be set. + The default is infinite. Note that the size of read requests is + limited anyway to 32 pages (which is 128kbyte on i386). + +How do non-privileged mounts work? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since the mount() system call is a privileged operation, a helper +program (fusermount) is needed, which is installed setuid root. + +The implication of providing non-privileged mounts is that the mount +owner must not be able to use this capability to compromise the +system. Obvious requirements arising from this are: + + A) mount owner should not be able to get elevated privileges with the + help of the mounted filesystem + + B) mount owner should not get illegitimate access to information from + other users' and the super user's processes + + C) mount owner should not be able to induce undesired behavior in + other users' or the super user's processes + +How are requirements fulfilled? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + A) The mount owner could gain elevated privileges by either: + + 1) creating a filesystem containing a device file, then opening + this device + + 2) creating a filesystem containing a suid or sgid application, + then executing this application + + The solution is not to allow opening device files and ignore + setuid and setgid bits when executing programs. To ensure this + fusermount always adds "nosuid" and "nodev" to the mount options + for non-privileged mounts. + + B) If another user is accessing files or directories in the + filesystem, the filesystem daemon serving requests can record the + exact sequence and timing of operations performed. This + information is otherwise inaccessible to the mount owner, so this + counts as an information leak. + + The solution to this problem will be presented in point 2) of C). + + C) There are several ways in which the mount owner can induce + undesired behavior in other users' processes, such as: + + 1) mounting a filesystem over a file or directory which the mount + owner could otherwise not be able to modify (or could only + make limited modifications). + + This is solved in fusermount, by checking the access + permissions on the mountpoint and only allowing the mount if + the mount owner can do unlimited modification (has write + access to the mountpoint, and mountpoint is not a "sticky" + directory) + + 2) Even if 1) is solved the mount owner can change the behavior + of other users' processes. + + i) It can slow down or indefinitely delay the execution of a + filesystem operation creating a DoS against the user or the + whole system. For example a suid application locking a + system file, and then accessing a file on the mount owner's + filesystem could be stopped, and thus causing the system + file to be locked forever. + + ii) It can present files or directories of unlimited length, or + directory structures of unlimited depth, possibly causing a + system process to eat up diskspace, memory or other + resources, again causing DoS. + + The solution to this as well as B) is not to allow processes + to access the filesystem, which could otherwise not be + monitored or manipulated by the mount owner. Since if the + mount owner can ptrace a process, it can do all of the above + without using a FUSE mount, the same criteria as used in + ptrace can be used to check if a process is allowed to access + the filesystem or not. + + Note that the ptrace check is not strictly necessary to + prevent B/2/i, it is enough to check if mount owner has enough + privilege to send signal to the process accessing the + filesystem, since SIGSTOP can be used to get a similar effect. + +I think these limitations are unacceptable? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a sysadmin trusts the users enough, or can ensure through other +measures, that system processes will never enter non-privileged +mounts, it can relax the last limitation with a "user_allow_other" +config option. If this config option is set, the mounting user can +add the "allow_other" mount option which disables the check for other +users' processes. + +Kernel - userspace interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following diagram shows how a filesystem operation (in this +example unlink) is performed in FUSE. + +NOTE: everything in this description is greatly simplified + + | "rm /mnt/fuse/file" | FUSE filesystem daemon + | | + | | >sys_read() + | | >fuse_dev_read() + | | >request_wait() + | | [sleep on fc->waitq] + | | + | >sys_unlink() | + | >fuse_unlink() | + | [get request from | + | fc->unused_list] | + | >request_send() | + | [queue req on fc->pending] | + | [wake up fc->waitq] | [woken up] + | >request_wait_answer() | + | [sleep on req->waitq] | + | | <request_wait() + | | [remove req from fc->pending] + | | [copy req to read buffer] + | | [add req to fc->processing] + | | <fuse_dev_read() + | | <sys_read() + | | + | | [perform unlink] + | | + | | >sys_write() + | | >fuse_dev_write() + | | [look up req in fc->processing] + | | [remove from fc->processing] + | | [copy write buffer to req] + | [woken up] | [wake up req->waitq] + | | <fuse_dev_write() + | | <sys_write() + | <request_wait_answer() | + | <request_send() | + | [add request to | + | fc->unused_list] | + | <fuse_unlink() | + | <sys_unlink() | + +There are a couple of ways in which to deadlock a FUSE filesystem. +Since we are talking about unprivileged userspace programs, +something must be done about these. + +Scenario 1 - Simple deadlock +----------------------------- + + | "rm /mnt/fuse/file" | FUSE filesystem daemon + | | + | >sys_unlink("/mnt/fuse/file") | + | [acquire inode semaphore | + | for "file"] | + | >fuse_unlink() | + | [sleep on req->waitq] | + | | <sys_read() + | | >sys_unlink("/mnt/fuse/file") + | | [acquire inode semaphore + | | for "file"] + | | *DEADLOCK* + +The solution for this is to allow requests to be interrupted while +they are in userspace: + + | [interrupted by signal] | + | <fuse_unlink() | + | [release semaphore] | [semaphore acquired] + | <sys_unlink() | + | | >fuse_unlink() + | | [queue req on fc->pending] + | | [wake up fc->waitq] + | | [sleep on req->waitq] + +If the filesystem daemon was single threaded, this will stop here, +since there's no other thread to dequeue and execute the request. +In this case the solution is to kill the FUSE daemon as well. If +there are multiple serving threads, you just have to kill them as +long as any remain. + +Moral: a filesystem which deadlocks, can soon find itself dead. + +Scenario 2 - Tricky deadlock +---------------------------- + +This one needs a carefully crafted filesystem. It's a variation on +the above, only the call back to the filesystem is not explicit, +but is caused by a pagefault. + + | Kamikaze filesystem thread 1 | Kamikaze filesystem thread 2 + | | + | [fd = open("/mnt/fuse/file")] | [request served normally] + | [mmap fd to 'addr'] | + | [close fd] | [FLUSH triggers 'magic' flag] + | [read a byte from addr] | + | >do_page_fault() | + | [find or create page] | + | [lock page] | + | >fuse_readpage() | + | [queue READ request] | + | [sleep on req->waitq] | + | | [read request to buffer] + | | [create reply header before addr] + | | >sys_write(addr - headerlength) + | | >fuse_dev_write() + | | [look up req in fc->processing] + | | [remove from fc->processing] + | | [copy write buffer to req] + | | >do_page_fault() + | | [find or create page] + | | [lock page] + | | * DEADLOCK * + +Solution is again to let the the request be interrupted (not +elaborated further). + +An additional problem is that while the write buffer is being +copied to the request, the request must not be interrupted. This +is because the destination address of the copy may not be valid +after the request is interrupted. + +This is solved with doing the copy atomically, and allowing +interruption while the page(s) belonging to the write buffer are +faulted with get_user_pages(). The 'req->locked' flag indicates +when the copy is taking place, and interruption is delayed until +this flag is unset. + diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index 9c3e4cc7b1a63..21021c3564815 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_FUSE_FS) += fuse.o -fuse-objs := inode.o +fuse-objs := dev.o inode.o diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c new file mode 100644 index 0000000000000..9aaf10a6588f0 --- /dev/null +++ b/fs/fuse/dev.c @@ -0,0 +1,884 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include "fuse_i.h" + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/poll.h> +#include <linux/uio.h> +#include <linux/miscdevice.h> +#include <linux/pagemap.h> +#include <linux/file.h> +#include <linux/slab.h> + +MODULE_ALIAS_MISCDEV(FUSE_MINOR); + +static kmem_cache_t *fuse_req_cachep; + +static inline struct fuse_conn *fuse_get_conn(struct file *file) +{ + struct fuse_conn *fc; + spin_lock(&fuse_lock); + fc = file->private_data; + if (fc && !fc->sb) + fc = NULL; + spin_unlock(&fuse_lock); + return fc; +} + +static inline void fuse_request_init(struct fuse_req *req) +{ + memset(req, 0, sizeof(*req)); + INIT_LIST_HEAD(&req->list); + init_waitqueue_head(&req->waitq); + atomic_set(&req->count, 1); +} + +struct fuse_req *fuse_request_alloc(void) +{ + struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL); + if (req) + fuse_request_init(req); + return req; +} + +void fuse_request_free(struct fuse_req *req) +{ + kmem_cache_free(fuse_req_cachep, req); +} + +static inline void block_sigs(sigset_t *oldset) +{ + sigset_t mask; + + siginitsetinv(&mask, sigmask(SIGKILL)); + sigprocmask(SIG_BLOCK, &mask, oldset); +} + +static inline void restore_sigs(sigset_t *oldset) +{ + sigprocmask(SIG_SETMASK, oldset, NULL); +} + +void fuse_reset_request(struct fuse_req *req) +{ + int preallocated = req->preallocated; + BUG_ON(atomic_read(&req->count) != 1); + fuse_request_init(req); + req->preallocated = preallocated; +} + +static void __fuse_get_request(struct fuse_req *req) +{ + atomic_inc(&req->count); +} + +/* Must be called with > 1 refcount */ +static void __fuse_put_request(struct fuse_req *req) +{ + BUG_ON(atomic_read(&req->count) < 2); + atomic_dec(&req->count); +} + +static struct fuse_req *do_get_request(struct fuse_conn *fc) +{ + struct fuse_req *req; + + spin_lock(&fuse_lock); + BUG_ON(list_empty(&fc->unused_list)); + req = list_entry(fc->unused_list.next, struct fuse_req, list); + list_del_init(&req->list); + spin_unlock(&fuse_lock); + fuse_request_init(req); + req->preallocated = 1; + req->in.h.uid = current->fsuid; + req->in.h.gid = current->fsgid; + req->in.h.pid = current->pid; + return req; +} + +struct fuse_req *fuse_get_request(struct fuse_conn *fc) +{ + if (down_interruptible(&fc->outstanding_sem)) + return NULL; + return do_get_request(fc); +} + +/* + * Non-interruptible version of the above function is for operations + * which can't legally return -ERESTART{SYS,NOINTR}. This can still + * return NULL, but only in case the signal is SIGKILL. + */ +struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc) +{ + int intr; + sigset_t oldset; + + block_sigs(&oldset); + intr = down_interruptible(&fc->outstanding_sem); + restore_sigs(&oldset); + return intr ? NULL : do_get_request(fc); +} + +static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req) +{ + spin_lock(&fuse_lock); + if (req->preallocated) + list_add(&req->list, &fc->unused_list); + else + fuse_request_free(req); + + /* If we are in debt decrease that first */ + if (fc->outstanding_debt) + fc->outstanding_debt--; + else + up(&fc->outstanding_sem); + spin_unlock(&fuse_lock); +} + +void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) +{ + if (atomic_dec_and_test(&req->count)) + fuse_putback_request(fc, req); +} + +/* + * This function is called when a request is finished. Either a reply + * has arrived or it was interrupted (and not yet sent) or some error + * occured during communication with userspace, or the device file was + * closed. It decreases the referece count for the request. In case + * of a background request the referece to the stored objects are + * released. The requester thread is woken up (if still waiting), and + * finally the request is either freed or put on the unused_list + * + * Called with fuse_lock, unlocks it + */ +static void request_end(struct fuse_conn *fc, struct fuse_req *req) +{ + int putback; + req->finished = 1; + putback = atomic_dec_and_test(&req->count); + spin_unlock(&fuse_lock); + if (req->background) { + if (req->inode) + iput(req->inode); + if (req->inode2) + iput(req->inode2); + if (req->file) + fput(req->file); + } + wake_up(&req->waitq); + if (req->in.h.opcode == FUSE_INIT) { + int i; + + if (req->misc.init_in_out.major != FUSE_KERNEL_VERSION) + fc->conn_error = 1; + + /* After INIT reply is received other requests can go + out. So do (FUSE_MAX_OUTSTANDING - 1) number of + up()s on outstanding_sem. The last up() is done in + fuse_putback_request() */ + for (i = 1; i < FUSE_MAX_OUTSTANDING; i++) + up(&fc->outstanding_sem); + } + if (putback) + fuse_putback_request(fc, req); +} + +static void background_request(struct fuse_req *req) +{ + /* Need to get hold of the inode(s) and/or file used in the + request, so FORGET and RELEASE are not sent too early */ + req->background = 1; + if (req->inode) + req->inode = igrab(req->inode); + if (req->inode2) + req->inode2 = igrab(req->inode2); + if (req->file) + get_file(req->file); +} + +static int request_wait_answer_nonint(struct fuse_req *req) +{ + int err; + sigset_t oldset; + block_sigs(&oldset); + err = wait_event_interruptible(req->waitq, req->finished); + restore_sigs(&oldset); + return err; +} + +/* Called with fuse_lock held. Releases, and then reacquires it. */ +static void request_wait_answer(struct fuse_req *req, int interruptible) +{ + int intr; + + spin_unlock(&fuse_lock); + if (interruptible) + intr = wait_event_interruptible(req->waitq, req->finished); + else + intr = request_wait_answer_nonint(req); + spin_lock(&fuse_lock); + if (intr && interruptible && req->sent) { + /* If request is already in userspace, only allow KILL + signal to interrupt */ + spin_unlock(&fuse_lock); + intr = request_wait_answer_nonint(req); + spin_lock(&fuse_lock); + } + if (!intr) + return; + + if (!interruptible || req->sent) + req->out.h.error = -EINTR; + else + req->out.h.error = -ERESTARTNOINTR; + + req->interrupted = 1; + if (req->locked) { + /* This is uninterruptible sleep, because data is + being copied to/from the buffers of req. During + locked state, there mustn't be any filesystem + operation (e.g. page fault), since that could lead + to deadlock */ + spin_unlock(&fuse_lock); + wait_event(req->waitq, !req->locked); + spin_lock(&fuse_lock); + } + if (!req->sent && !list_empty(&req->list)) { + list_del(&req->list); + __fuse_put_request(req); + } else if (!req->finished && req->sent) + background_request(req); +} + +static unsigned len_args(unsigned numargs, struct fuse_arg *args) +{ + unsigned nbytes = 0; + unsigned i; + + for (i = 0; i < numargs; i++) + nbytes += args[i].size; + + return nbytes; +} + +static void queue_request(struct fuse_conn *fc, struct fuse_req *req) +{ + fc->reqctr++; + /* zero is special */ + if (fc->reqctr == 0) + fc->reqctr = 1; + req->in.h.unique = fc->reqctr; + req->in.h.len = sizeof(struct fuse_in_header) + + len_args(req->in.numargs, (struct fuse_arg *) req->in.args); + if (!req->preallocated) { + /* If request is not preallocated (either FORGET or + RELEASE), then still decrease outstanding_sem, so + user can't open infinite number of files while not + processing the RELEASE requests. However for + efficiency do it without blocking, so if down() + would block, just increase the debt instead */ + if (down_trylock(&fc->outstanding_sem)) + fc->outstanding_debt++; + } + list_add_tail(&req->list, &fc->pending); + wake_up(&fc->waitq); +} + +static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req, + int interruptible) +{ + req->isreply = 1; + spin_lock(&fuse_lock); + if (!fc->file) + req->out.h.error = -ENOTCONN; + else if (fc->conn_error) + req->out.h.error = -ECONNREFUSED; + else { + queue_request(fc, req); + /* acquire extra reference, since request is still needed + after request_end() */ + __fuse_get_request(req); + + request_wait_answer(req, interruptible); + } + spin_unlock(&fuse_lock); +} + +void request_send(struct fuse_conn *fc, struct fuse_req *req) +{ + request_send_wait(fc, req, 1); +} + +/* + * Non-interruptible version of the above function is for operations + * which can't legally return -ERESTART{SYS,NOINTR}. This can still + * be interrupted but only with SIGKILL. + */ +void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req) +{ + request_send_wait(fc, req, 0); +} + +static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) +{ + spin_lock(&fuse_lock); + if (fc->file) { + queue_request(fc, req); + spin_unlock(&fuse_lock); + } else { + req->out.h.error = -ENOTCONN; + request_end(fc, req); + } +} + +void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) +{ + req->isreply = 0; + request_send_nowait(fc, req); +} + +void request_send_background(struct fuse_conn *fc, struct fuse_req *req) +{ + req->isreply = 1; + background_request(req); + request_send_nowait(fc, req); +} + +void fuse_send_init(struct fuse_conn *fc) +{ + /* This is called from fuse_read_super() so there's guaranteed + to be a request available */ + struct fuse_req *req = do_get_request(fc); + struct fuse_init_in_out *arg = &req->misc.init_in_out; + arg->major = FUSE_KERNEL_VERSION; + arg->minor = FUSE_KERNEL_MINOR_VERSION; + req->in.h.opcode = FUSE_INIT; + req->in.numargs = 1; + req->in.args[0].size = sizeof(*arg); + req->in.args[0].value = arg; + req->out.numargs = 1; + req->out.args[0].size = sizeof(*arg); + req->out.args[0].value = arg; + request_send_background(fc, req); +} + +/* + * Lock the request. Up to the next unlock_request() there mustn't be + * anything that could cause a page-fault. If the request was already + * interrupted bail out. + */ +static inline int lock_request(struct fuse_req *req) +{ + int err = 0; + if (req) { + spin_lock(&fuse_lock); + if (req->interrupted) + err = -ENOENT; + else + req->locked = 1; + spin_unlock(&fuse_lock); + } + return err; +} + +/* + * Unlock request. If it was interrupted during being locked, the + * requester thread is currently waiting for it to be unlocked, so + * wake it up. + */ +static inline void unlock_request(struct fuse_req *req) +{ + if (req) { + spin_lock(&fuse_lock); + req->locked = 0; + if (req->interrupted) + wake_up(&req->waitq); + spin_unlock(&fuse_lock); + } +} + +struct fuse_copy_state { + int write; + struct fuse_req *req; + const struct iovec *iov; + unsigned long nr_segs; + unsigned long seglen; + unsigned long addr; + struct page *pg; + void *mapaddr; + void *buf; + unsigned len; +}; + +static void fuse_copy_init(struct fuse_copy_state *cs, int write, + struct fuse_req *req, const struct iovec *iov, + unsigned long nr_segs) +{ + memset(cs, 0, sizeof(*cs)); + cs->write = write; + cs->req = req; + cs->iov = iov; + cs->nr_segs = nr_segs; +} + +/* Unmap and put previous page of userspace buffer */ +static inline void fuse_copy_finish(struct fuse_copy_state *cs) +{ + if (cs->mapaddr) { + kunmap_atomic(cs->mapaddr, KM_USER0); + if (cs->write) { + flush_dcache_page(cs->pg); + set_page_dirty_lock(cs->pg); + } + put_page(cs->pg); + cs->mapaddr = NULL; + } +} + +/* + * Get another pagefull of userspace buffer, and map it to kernel + * address space, and lock request + */ +static int fuse_copy_fill(struct fuse_copy_state *cs) +{ + unsigned long offset; + int err; + + unlock_request(cs->req); + fuse_copy_finish(cs); + if (!cs->seglen) { + BUG_ON(!cs->nr_segs); + cs->seglen = cs->iov[0].iov_len; + cs->addr = (unsigned long) cs->iov[0].iov_base; + cs->iov ++; + cs->nr_segs --; + } + down_read(¤t->mm->mmap_sem); + err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0, + &cs->pg, NULL); + up_read(¤t->mm->mmap_sem); + if (err < 0) + return err; + BUG_ON(err != 1); + offset = cs->addr % PAGE_SIZE; + cs->mapaddr = kmap_atomic(cs->pg, KM_USER0); + cs->buf = cs->mapaddr + offset; + cs->len = min(PAGE_SIZE - offset, cs->seglen); + cs->seglen -= cs->len; + cs->addr += cs->len; + + return lock_request(cs->req); +} + +/* Do as much copy to/from userspace buffer as we can */ +static inline int fuse_copy_do(struct fuse_copy_state *cs, void **val, + unsigned *size) +{ + unsigned ncpy = min(*size, cs->len); + if (val) { + if (cs->write) + memcpy(cs->buf, *val, ncpy); + else + memcpy(*val, cs->buf, ncpy); + *val += ncpy; + } + *size -= ncpy; + cs->len -= ncpy; + cs->buf += ncpy; + return ncpy; +} + +/* + * Copy a page in the request to/from the userspace buffer. Must be + * done atomically + */ +static inline int fuse_copy_page(struct fuse_copy_state *cs, struct page *page, + unsigned offset, unsigned count, int zeroing) +{ + if (page && zeroing && count < PAGE_SIZE) { + void *mapaddr = kmap_atomic(page, KM_USER1); + memset(mapaddr, 0, PAGE_SIZE); + kunmap_atomic(mapaddr, KM_USER1); + } + while (count) { + int err; + if (!cs->len && (err = fuse_copy_fill(cs))) + return err; + if (page) { + void *mapaddr = kmap_atomic(page, KM_USER1); + void *buf = mapaddr + offset; + offset += fuse_copy_do(cs, &buf, &count); + kunmap_atomic(mapaddr, KM_USER1); + } else + offset += fuse_copy_do(cs, NULL, &count); + } + if (page && !cs->write) + flush_dcache_page(page); + return 0; +} + +/* Copy pages in the request to/from userspace buffer */ +static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes, + int zeroing) +{ + unsigned i; + struct fuse_req *req = cs->req; + unsigned offset = req->page_offset; + unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset); + + for (i = 0; i < req->num_pages && (nbytes || zeroing); i++) { + struct page *page = req->pages[i]; + int err = fuse_copy_page(cs, page, offset, count, zeroing); + if (err) + return err; + + nbytes -= count; + count = min(nbytes, (unsigned) PAGE_SIZE); + offset = 0; + } + return 0; +} + +/* Copy a single argument in the request to/from userspace buffer */ +static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size) +{ + while (size) { + int err; + if (!cs->len && (err = fuse_copy_fill(cs))) + return err; + fuse_copy_do(cs, &val, &size); + } + return 0; +} + +/* Copy request arguments to/from userspace buffer */ +static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs, + unsigned argpages, struct fuse_arg *args, + int zeroing) +{ + int err = 0; + unsigned i; + + for (i = 0; !err && i < numargs; i++) { + struct fuse_arg *arg = &args[i]; + if (i == numargs - 1 && argpages) + err = fuse_copy_pages(cs, arg->size, zeroing); + else + err = fuse_copy_one(cs, arg->value, arg->size); + } + return err; +} + +/* Wait until a request is available on the pending list */ +static void request_wait(struct fuse_conn *fc) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue_exclusive(&fc->waitq, &wait); + while (fc->sb && list_empty(&fc->pending)) { + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) + break; + + spin_unlock(&fuse_lock); + schedule(); + spin_lock(&fuse_lock); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&fc->waitq, &wait); +} + +/* + * Read a single request into the userspace filesystem's buffer. This + * function waits until a request is available, then removes it from + * the pending list and copies request data to userspace buffer. If + * no reply is needed (FORGET) or request has been interrupted or + * there was an error during the copying then it's finished by calling + * request_end(). Otherwise add it to the processing list, and set + * the 'sent' flag. + */ +static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov, + unsigned long nr_segs, loff_t *off) +{ + int err; + struct fuse_conn *fc; + struct fuse_req *req; + struct fuse_in *in; + struct fuse_copy_state cs; + unsigned reqsize; + + spin_lock(&fuse_lock); + fc = file->private_data; + err = -EPERM; + if (!fc) + goto err_unlock; + request_wait(fc); + err = -ENODEV; + if (!fc->sb) + goto err_unlock; + err = -ERESTARTSYS; + if (list_empty(&fc->pending)) + goto err_unlock; + + req = list_entry(fc->pending.next, struct fuse_req, list); + list_del_init(&req->list); + spin_unlock(&fuse_lock); + + in = &req->in; + reqsize = req->in.h.len; + fuse_copy_init(&cs, 1, req, iov, nr_segs); + err = -EINVAL; + if (iov_length(iov, nr_segs) >= reqsize) { + err = fuse_copy_one(&cs, &in->h, sizeof(in->h)); + if (!err) + err = fuse_copy_args(&cs, in->numargs, in->argpages, + (struct fuse_arg *) in->args, 0); + } + fuse_copy_finish(&cs); + + spin_lock(&fuse_lock); + req->locked = 0; + if (!err && req->interrupted) + err = -ENOENT; + if (err) { + if (!req->interrupted) + req->out.h.error = -EIO; + request_end(fc, req); + return err; + } + if (!req->isreply) + request_end(fc, req); + else { + req->sent = 1; + list_add_tail(&req->list, &fc->processing); + spin_unlock(&fuse_lock); + } + return reqsize; + + err_unlock: + spin_unlock(&fuse_lock); + return err; +} + +static ssize_t fuse_dev_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *off) +{ + struct iovec iov; + iov.iov_len = nbytes; + iov.iov_base = buf; + return fuse_dev_readv(file, &iov, 1, off); +} + +/* Look up request on processing list by unique ID */ +static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique) +{ + struct list_head *entry; + + list_for_each(entry, &fc->processing) { + struct fuse_req *req; + req = list_entry(entry, struct fuse_req, list); + if (req->in.h.unique == unique) + return req; + } + return NULL; +} + +static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out, + unsigned nbytes) +{ + unsigned reqsize = sizeof(struct fuse_out_header); + + if (out->h.error) + return nbytes != reqsize ? -EINVAL : 0; + + reqsize += len_args(out->numargs, out->args); + + if (reqsize < nbytes || (reqsize > nbytes && !out->argvar)) + return -EINVAL; + else if (reqsize > nbytes) { + struct fuse_arg *lastarg = &out->args[out->numargs-1]; + unsigned diffsize = reqsize - nbytes; + if (diffsize > lastarg->size) + return -EINVAL; + lastarg->size -= diffsize; + } + return fuse_copy_args(cs, out->numargs, out->argpages, out->args, + out->page_zeroing); +} + +/* + * Write a single reply to a request. First the header is copied from + * the write buffer. The request is then searched on the processing + * list by the unique ID found in the header. If found, then remove + * it from the list and copy the rest of the buffer to the request. + * The request is finished by calling request_end() + */ +static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov, + unsigned long nr_segs, loff_t *off) +{ + int err; + unsigned nbytes = iov_length(iov, nr_segs); + struct fuse_req *req; + struct fuse_out_header oh; + struct fuse_copy_state cs; + struct fuse_conn *fc = fuse_get_conn(file); + if (!fc) + return -ENODEV; + + fuse_copy_init(&cs, 0, NULL, iov, nr_segs); + if (nbytes < sizeof(struct fuse_out_header)) + return -EINVAL; + + err = fuse_copy_one(&cs, &oh, sizeof(oh)); + if (err) + goto err_finish; + err = -EINVAL; + if (!oh.unique || oh.error <= -1000 || oh.error > 0 || + oh.len != nbytes) + goto err_finish; + + spin_lock(&fuse_lock); + req = request_find(fc, oh.unique); + err = -EINVAL; + if (!req) + goto err_unlock; + + list_del_init(&req->list); + if (req->interrupted) { + request_end(fc, req); + fuse_copy_finish(&cs); + return -ENOENT; + } + req->out.h = oh; + req->locked = 1; + cs.req = req; + spin_unlock(&fuse_lock); + + err = copy_out_args(&cs, &req->out, nbytes); + fuse_copy_finish(&cs); + + spin_lock(&fuse_lock); + req->locked = 0; + if (!err) { + if (req->interrupted) + err = -ENOENT; + } else if (!req->interrupted) + req->out.h.error = -EIO; + request_end(fc, req); + + return err ? err : nbytes; + + err_unlock: + spin_unlock(&fuse_lock); + err_finish: + fuse_copy_finish(&cs); + return err; +} + +static ssize_t fuse_dev_write(struct file *file, const char __user *buf, + size_t nbytes, loff_t *off) +{ + struct iovec iov; + iov.iov_len = nbytes; + iov.iov_base = (char __user *) buf; + return fuse_dev_writev(file, &iov, 1, off); +} + +static unsigned fuse_dev_poll(struct file *file, poll_table *wait) +{ + struct fuse_conn *fc = fuse_get_conn(file); + unsigned mask = POLLOUT | POLLWRNORM; + + if (!fc) + return -ENODEV; + + poll_wait(file, &fc->waitq, wait); + + spin_lock(&fuse_lock); + if (!list_empty(&fc->pending)) + mask |= POLLIN | POLLRDNORM; + spin_unlock(&fuse_lock); + + return mask; +} + +/* Abort all requests on the given list (pending or processing) */ +static void end_requests(struct fuse_conn *fc, struct list_head *head) +{ + while (!list_empty(head)) { + struct fuse_req *req; + req = list_entry(head->next, struct fuse_req, list); + list_del_init(&req->list); + req->out.h.error = -ECONNABORTED; + request_end(fc, req); + spin_lock(&fuse_lock); + } +} + +static int fuse_dev_release(struct inode *inode, struct file *file) +{ + struct fuse_conn *fc; + + spin_lock(&fuse_lock); + fc = file->private_data; + if (fc) { + fc->file = NULL; + end_requests(fc, &fc->pending); + end_requests(fc, &fc->processing); + fuse_release_conn(fc); + } + spin_unlock(&fuse_lock); + return 0; +} + +struct file_operations fuse_dev_operations = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = fuse_dev_read, + .readv = fuse_dev_readv, + .write = fuse_dev_write, + .writev = fuse_dev_writev, + .poll = fuse_dev_poll, + .release = fuse_dev_release, +}; + +static struct miscdevice fuse_miscdevice = { + .minor = FUSE_MINOR, + .name = "fuse", + .fops = &fuse_dev_operations, +}; + +int __init fuse_dev_init(void) +{ + int err = -ENOMEM; + fuse_req_cachep = kmem_cache_create("fuse_request", + sizeof(struct fuse_req), + 0, 0, NULL, NULL); + if (!fuse_req_cachep) + goto out; + + err = misc_register(&fuse_miscdevice); + if (err) + goto out_cache_clean; + + return 0; + + out_cache_clean: + kmem_cache_destroy(fuse_req_cachep); + out: + return err; +} + +void fuse_dev_cleanup(void) +{ + misc_deregister(&fuse_miscdevice); + kmem_cache_destroy(fuse_req_cachep); +} diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index eed6e89ce01f7..50ad6a0c39bfa 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -15,6 +15,12 @@ #include <linux/backing-dev.h> #include <asm/semaphore.h> +/** Max number of pages that can be used in a single read request */ +#define FUSE_MAX_PAGES_PER_REQ 32 + +/** If more requests are outstanding, then the operation will block */ +#define FUSE_MAX_OUTSTANDING 10 + /** FUSE inode */ struct fuse_inode { /** Inode data */ @@ -28,6 +34,123 @@ struct fuse_inode { unsigned long i_time; }; +/** One input argument of a request */ +struct fuse_in_arg { + unsigned size; + const void *value; +}; + +/** The request input */ +struct fuse_in { + /** The request header */ + struct fuse_in_header h; + + /** True if the data for the last argument is in req->pages */ + unsigned argpages:1; + + /** Number of arguments */ + unsigned numargs; + + /** Array of arguments */ + struct fuse_in_arg args[3]; +}; + +/** One output argument of a request */ +struct fuse_arg { + unsigned size; + void *value; +}; + +/** The request output */ +struct fuse_out { + /** Header returned from userspace */ + struct fuse_out_header h; + + /** Last argument is variable length (can be shorter than + arg->size) */ + unsigned argvar:1; + + /** Last argument is a list of pages to copy data to */ + unsigned argpages:1; + + /** Zero partially or not copied pages */ + unsigned page_zeroing:1; + + /** Number or arguments */ + unsigned numargs; + + /** Array of arguments */ + struct fuse_arg args[3]; +}; + +struct fuse_req; +struct fuse_conn; + +/** + * A request to the client + */ +struct fuse_req { + /** This can be on either unused_list, pending or processing + lists in fuse_conn */ + struct list_head list; + + /** refcount */ + atomic_t count; + + /** True if the request has reply */ + unsigned isreply:1; + + /** The request is preallocated */ + unsigned preallocated:1; + + /** The request was interrupted */ + unsigned interrupted:1; + + /** Request is sent in the background */ + unsigned background:1; + + /** Data is being copied to/from the request */ + unsigned locked:1; + + /** Request has been sent to userspace */ + unsigned sent:1; + + /** The request is finished */ + unsigned finished:1; + + /** The request input */ + struct fuse_in in; + + /** The request output */ + struct fuse_out out; + + /** Used to wake up the task waiting for completion of request*/ + wait_queue_head_t waitq; + + /** Data for asynchronous requests */ + union { + struct fuse_init_in_out init_in_out; + } misc; + + /** page vector */ + struct page *pages[FUSE_MAX_PAGES_PER_REQ]; + + /** number of pages in vector */ + unsigned num_pages; + + /** offset of data on first page */ + unsigned page_offset; + + /** Inode used in the request */ + struct inode *inode; + + /** Second inode used in the request (or NULL) */ + struct inode *inode2; + + /** File used in the request (or NULL) */ + struct file *file; +}; + /** * A Fuse connection. * @@ -39,9 +162,37 @@ struct fuse_conn { /** The superblock of the mounted filesystem */ struct super_block *sb; + /** The opened client device */ + struct file *file; + /** The user id for this mount */ uid_t user_id; + /** Readers of the connection are waiting on this */ + wait_queue_head_t waitq; + + /** The list of pending requests */ + struct list_head pending; + + /** The list of requests being processed */ + struct list_head processing; + + /** Controls the maximum number of outstanding requests */ + struct semaphore outstanding_sem; + + /** This counts the number of outstanding requests if + outstanding_sem would go negative */ + unsigned outstanding_debt; + + /** The list of unused requests */ + struct list_head unused_list; + + /** The next unique request id */ + u64 reqctr; + + /** Connection failed (version mismatch) */ + unsigned conn_error : 1; + /** Backing dev info */ struct backing_dev_info bdi; }; @@ -71,13 +222,20 @@ static inline u64 get_node_id(struct inode *inode) return get_fuse_inode(inode)->nodeid; } +/** Device operations */ +extern struct file_operations fuse_dev_operations; + /** * This is the single global spinlock which protects FUSE's structures * * The following data is protected by this lock: * + * - the private_data field of the device file * - the s_fs_info field of the super block + * - unused_list, pending, processing lists in fuse_conn + * - the unique request ID counter reqctr in fuse_conn * - the sb (super_block) field in fuse_conn + * - the file (device file) field in fuse_conn */ extern spinlock_t fuse_lock; @@ -87,3 +245,68 @@ extern spinlock_t fuse_lock; */ void fuse_release_conn(struct fuse_conn *fc); +/** + * Initialize the client device + */ +int fuse_dev_init(void); + +/** + * Cleanup the client device + */ +void fuse_dev_cleanup(void); + +/** + * Allocate a request + */ +struct fuse_req *fuse_request_alloc(void); + +/** + * Free a request + */ +void fuse_request_free(struct fuse_req *req); + +/** + * Reinitialize a request, the preallocated flag is left unmodified + */ +void fuse_reset_request(struct fuse_req *req); + +/** + * Reserve a preallocated request + */ +struct fuse_req *fuse_get_request(struct fuse_conn *fc); + +/** + * Reserve a preallocated request, only interruptible by SIGKILL + */ +struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc); + +/** + * Decrement reference count of a request. If count goes to zero put + * on unused list (preallocated) or free reqest (not preallocated). + */ +void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); + +/** + * Send a request (synchronous, interruptible) + */ +void request_send(struct fuse_conn *fc, struct fuse_req *req); + +/** + * Send a request (synchronous, non-interruptible except by SIGKILL) + */ +void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req); + +/** + * Send a request with no reply + */ +void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); + +/** + * Send a request in the background + */ +void request_send_background(struct fuse_conn *fc, struct fuse_req *req); + +/** + * Send the INIT message + */ +void fuse_send_init(struct fuse_conn *fc); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index ea6339c2b6a1b..33fad334ba70e 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -151,6 +151,8 @@ static void fuse_put_super(struct super_block *sb) mount_count --; fc->sb = NULL; fc->user_id = 0; + /* Flush all readers on this fs */ + wake_up_all(&fc->waitq); fuse_release_conn(fc); *get_fuse_conn_super_p(sb) = NULL; spin_unlock(&fuse_lock); @@ -229,22 +231,51 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) return 0; } -void fuse_release_conn(struct fuse_conn *fc) +static void free_conn(struct fuse_conn *fc) { + while (!list_empty(&fc->unused_list)) { + struct fuse_req *req; + req = list_entry(fc->unused_list.next, struct fuse_req, list); + list_del(&req->list); + fuse_request_free(req); + } kfree(fc); } +/* Must be called with the fuse lock held */ +void fuse_release_conn(struct fuse_conn *fc) +{ + if (!fc->sb && !fc->file) + free_conn(fc); +} + static struct fuse_conn *new_conn(void) { struct fuse_conn *fc; fc = kmalloc(sizeof(*fc), GFP_KERNEL); if (fc != NULL) { + int i; memset(fc, 0, sizeof(*fc)); fc->sb = NULL; + fc->file = NULL; fc->user_id = 0; + init_waitqueue_head(&fc->waitq); + INIT_LIST_HEAD(&fc->pending); + INIT_LIST_HEAD(&fc->processing); + INIT_LIST_HEAD(&fc->unused_list); + sema_init(&fc->outstanding_sem, 0); + for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { + struct fuse_req *req = fuse_request_alloc(); + if (!req) { + free_conn(fc); + return NULL; + } + list_add(&req->list, &fc->unused_list); + } fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; fc->bdi.unplug_io_fn = default_unplug_io_fn; + fc->reqctr = 0; } return fc; } @@ -253,11 +284,20 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) { struct fuse_conn *fc; + if (file->f_op != &fuse_dev_operations) + return ERR_PTR(-EINVAL); fc = new_conn(); if (fc == NULL) - return NULL; + return ERR_PTR(-ENOMEM); spin_lock(&fuse_lock); - fc->sb = sb; + if (file->private_data) { + free_conn(fc); + fc = ERR_PTR(-EINVAL); + } else { + file->private_data = fc; + fc->sb = sb; + fc->file = file; + } spin_unlock(&fuse_lock); return fc; } @@ -315,8 +355,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) fc = get_conn(file, sb); fput(file); - if (fc == NULL) - return -EINVAL; + if (IS_ERR(fc)) + return PTR_ERR(fc); fc->user_id = d.user_id; @@ -336,6 +376,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) iput(root); goto err; } + fuse_send_init(fc); return 0; err: @@ -411,8 +452,14 @@ static int __init fuse_init(void) if (res) goto err; + res = fuse_dev_init(); + if (res) + goto err_fs_cleanup; + return 0; + err_fs_cleanup: + fuse_fs_cleanup(); err: return res; } @@ -422,6 +469,7 @@ static void __exit fuse_exit(void) printk(KERN_DEBUG "fuse exit\n"); fuse_fs_cleanup(); + fuse_dev_cleanup(); } module_init(fuse_init); diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 2b1f4ae01e9de..a1aebd7104c42 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -11,7 +11,7 @@ #include <asm/types.h> /** Version number of this interface */ -#define FUSE_KERNEL_VERSION 5 +#define FUSE_KERNEL_VERSION 6 /** Minor version number of this interface */ #define FUSE_KERNEL_MINOR_VERSION 1 @@ -19,6 +19,12 @@ /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 +/** The major number of the fuse character device */ +#define FUSE_MAJOR 10 + +/** The minor number of the fuse character device */ +#define FUSE_MINOR 229 + struct fuse_attr { __u64 ino; __u64 size; @@ -36,3 +42,31 @@ struct fuse_attr { __u32 rdev; }; +enum fuse_opcode { + FUSE_INIT = 26 +}; + +/* Conservative buffer size for the client */ +#define FUSE_MAX_IN 8192 + +struct fuse_init_in_out { + __u32 major; + __u32 minor; +}; + +struct fuse_in_header { + __u32 len; + __u32 opcode; + __u64 unique; + __u64 nodeid; + __u32 uid; + __u32 gid; + __u32 pid; +}; + +struct fuse_out_header { + __u32 len; + __s32 error; + __u64 unique; +}; + -- GitLab From e5e5558e923f35839108a12718494ecb73fb782f Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:28 -0700 Subject: [PATCH 266/563] [PATCH] FUSE - read-only operations This patch adds the read-only filesystem operations of FUSE. This contains the following files: o dir.c - directory, symlink and file-inode operations The following operations are added: o lookup o getattr o readlink o follow_link o directory open o readdir o directory release o permission o dentry revalidate o statfs Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/Makefile | 2 +- fs/fuse/dev.c | 9 + fs/fuse/dir.c | 413 +++++++++++++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 51 ++++++ fs/fuse/inode.c | 81 +++++++++ include/linux/fuse.h | 60 +++++++ 6 files changed, 615 insertions(+), 1 deletion(-) create mode 100644 fs/fuse/dir.c diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index 21021c3564815..c34e268a0ed34 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_FUSE_FS) += fuse.o -fuse-objs := dev.o inode.o +fuse-objs := dev.o dir.o inode.o diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 9aaf10a6588f0..e8f3170946f1f 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -691,6 +691,13 @@ static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique) return NULL; } +/* fget() needs to be done in this context */ +static void process_getdir(struct fuse_req *req) +{ + struct fuse_getdir_out_i *arg = req->out.args[0].value; + arg->file = fget(arg->fd); +} + static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out, unsigned nbytes) { @@ -770,6 +777,8 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov, if (!err) { if (req->interrupted) err = -ENOENT; + else if (req->in.h.opcode == FUSE_GETDIR && !oh.error) + process_getdir(req); } else if (!req->interrupted) req->out.h.error = -EIO; request_end(fc, req); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c new file mode 100644 index 0000000000000..a89730e70c587 --- /dev/null +++ b/fs/fuse/dir.c @@ -0,0 +1,413 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include "fuse_i.h" + +#include <linux/pagemap.h> +#include <linux/file.h> +#include <linux/gfp.h> +#include <linux/sched.h> +#include <linux/namei.h> + +static inline unsigned long time_to_jiffies(unsigned long sec, + unsigned long nsec) +{ + struct timespec ts = {sec, nsec}; + return jiffies + timespec_to_jiffies(&ts); +} + +static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, + struct dentry *entry, + struct fuse_entry_out *outarg) +{ + req->in.h.opcode = FUSE_LOOKUP; + req->in.h.nodeid = get_node_id(dir); + req->inode = dir; + req->in.numargs = 1; + req->in.args[0].size = entry->d_name.len + 1; + req->in.args[0].value = entry->d_name.name; + req->out.numargs = 1; + req->out.args[0].size = sizeof(struct fuse_entry_out); + req->out.args[0].value = outarg; +} + +static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) +{ + if (!entry->d_inode || is_bad_inode(entry->d_inode)) + return 0; + else if (time_after(jiffies, entry->d_time)) { + int err; + int version; + struct fuse_entry_out outarg; + struct inode *inode = entry->d_inode; + struct fuse_inode *fi = get_fuse_inode(inode); + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req = fuse_get_request_nonint(fc); + if (!req) + return 0; + + fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); + request_send_nonint(fc, req); + version = req->out.h.unique; + err = req->out.h.error; + fuse_put_request(fc, req); + if (err || outarg.nodeid != get_node_id(inode) || + (outarg.attr.mode ^ inode->i_mode) & S_IFMT) + return 0; + + fuse_change_attributes(inode, &outarg.attr); + inode->i_version = version; + entry->d_time = time_to_jiffies(outarg.entry_valid, + outarg.entry_valid_nsec); + fi->i_time = time_to_jiffies(outarg.attr_valid, + outarg.attr_valid_nsec); + } + return 1; +} + +static struct dentry_operations fuse_dentry_operations = { + .d_revalidate = fuse_dentry_revalidate, +}; + +static int fuse_lookup_iget(struct inode *dir, struct dentry *entry, + struct inode **inodep) +{ + int err; + int version; + struct fuse_entry_out outarg; + struct inode *inode = NULL; + struct fuse_conn *fc = get_fuse_conn(dir); + struct fuse_req *req; + + if (entry->d_name.len > FUSE_NAME_MAX) + return -ENAMETOOLONG; + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + fuse_lookup_init(req, dir, entry, &outarg); + request_send(fc, req); + version = req->out.h.unique; + err = req->out.h.error; + if (!err) { + inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, + &outarg.attr, version); + if (!inode) { + fuse_send_forget(fc, req, outarg.nodeid, version); + return -ENOMEM; + } + } + fuse_put_request(fc, req); + if (err && err != -ENOENT) + return err; + + if (inode) { + struct fuse_inode *fi = get_fuse_inode(inode); + entry->d_time = time_to_jiffies(outarg.entry_valid, + outarg.entry_valid_nsec); + fi->i_time = time_to_jiffies(outarg.attr_valid, + outarg.attr_valid_nsec); + } + + entry->d_op = &fuse_dentry_operations; + *inodep = inode; + return 0; +} + +int fuse_do_getattr(struct inode *inode) +{ + int err; + struct fuse_attr_out arg; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + req->in.h.opcode = FUSE_GETATTR; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->out.numargs = 1; + req->out.args[0].size = sizeof(arg); + req->out.args[0].value = &arg; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (!err) { + if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) { + make_bad_inode(inode); + err = -EIO; + } else { + struct fuse_inode *fi = get_fuse_inode(inode); + fuse_change_attributes(inode, &arg.attr); + fi->i_time = time_to_jiffies(arg.attr_valid, + arg.attr_valid_nsec); + } + } + return err; +} + +static int fuse_revalidate(struct dentry *entry) +{ + struct inode *inode = entry->d_inode; + struct fuse_inode *fi = get_fuse_inode(inode); + struct fuse_conn *fc = get_fuse_conn(inode); + + if (get_node_id(inode) == FUSE_ROOT_ID) { + if (current->fsuid != fc->user_id) + return -EACCES; + } else if (time_before_eq(jiffies, fi->i_time)) + return 0; + + return fuse_do_getattr(inode); +} + +static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + struct fuse_conn *fc = get_fuse_conn(inode); + + if (current->fsuid != fc->user_id) + return -EACCES; + else { + int mode = inode->i_mode; + if ((mask & MAY_WRITE) && IS_RDONLY(inode) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) + return -EROFS; + if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) + return -EACCES; + return 0; + } +} + +static int parse_dirfile(char *buf, size_t nbytes, struct file *file, + void *dstbuf, filldir_t filldir) +{ + while (nbytes >= FUSE_NAME_OFFSET) { + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; + size_t reclen = FUSE_DIRENT_SIZE(dirent); + int over; + if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX) + return -EIO; + if (reclen > nbytes) + break; + + over = filldir(dstbuf, dirent->name, dirent->namelen, + file->f_pos, dirent->ino, dirent->type); + if (over) + break; + + buf += reclen; + nbytes -= reclen; + file->f_pos = dirent->off; + } + + return 0; +} + +static int fuse_checkdir(struct file *cfile, struct file *file) +{ + struct inode *inode; + if (!cfile) + return -EIO; + inode = cfile->f_dentry->d_inode; + if (!S_ISREG(inode->i_mode)) { + fput(cfile); + return -EIO; + } + + file->private_data = cfile; + return 0; +} + +static int fuse_getdir(struct file *file) +{ + struct inode *inode = file->f_dentry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req = fuse_get_request(fc); + struct fuse_getdir_out_i outarg; + int err; + + if (!req) + return -ERESTARTNOINTR; + + req->in.h.opcode = FUSE_GETDIR; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->out.numargs = 1; + req->out.args[0].size = sizeof(struct fuse_getdir_out); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (!err) + err = fuse_checkdir(outarg.file, file); + return err; +} + +static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) +{ + struct file *cfile = file->private_data; + char *buf; + int ret; + + if (!cfile) { + ret = fuse_getdir(file); + if (ret) + return ret; + + cfile = file->private_data; + } + + buf = (char *) __get_free_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE); + if (ret > 0) + ret = parse_dirfile(buf, ret, file, dstbuf, filldir); + + free_page((unsigned long) buf); + return ret; +} + +static char *read_link(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req = fuse_get_request(fc); + char *link; + + if (!req) + return ERR_PTR(-ERESTARTNOINTR); + + link = (char *) __get_free_page(GFP_KERNEL); + if (!link) { + link = ERR_PTR(-ENOMEM); + goto out; + } + req->in.h.opcode = FUSE_READLINK; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->out.argvar = 1; + req->out.numargs = 1; + req->out.args[0].size = PAGE_SIZE - 1; + req->out.args[0].value = link; + request_send(fc, req); + if (req->out.h.error) { + free_page((unsigned long) link); + link = ERR_PTR(req->out.h.error); + } else + link[req->out.args[0].size] = '\0'; + out: + fuse_put_request(fc, req); + return link; +} + +static void free_link(char *link) +{ + if (!IS_ERR(link)) + free_page((unsigned long) link); +} + +static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + nd_set_link(nd, read_link(dentry)); + return NULL; +} + +static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) +{ + free_link(nd_get_link(nd)); +} + +static int fuse_dir_open(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +static int fuse_dir_release(struct inode *inode, struct file *file) +{ + struct file *cfile = file->private_data; + + if (cfile) + fput(cfile); + + return 0; +} + +static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, + struct kstat *stat) +{ + struct inode *inode = entry->d_inode; + int err = fuse_revalidate(entry); + if (!err) + generic_fillattr(inode, stat); + + return err; +} + +static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, + struct nameidata *nd) +{ + struct inode *inode; + int err = fuse_lookup_iget(dir, entry, &inode); + if (err) + return ERR_PTR(err); + if (inode && S_ISDIR(inode->i_mode)) { + /* Don't allow creating an alias to a directory */ + struct dentry *alias = d_find_alias(inode); + if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) { + dput(alias); + iput(inode); + return ERR_PTR(-EIO); + } + } + return d_splice_alias(inode, entry); +} + +static struct inode_operations fuse_dir_inode_operations = { + .lookup = fuse_lookup, + .permission = fuse_permission, + .getattr = fuse_getattr, +}; + +static struct file_operations fuse_dir_operations = { + .read = generic_read_dir, + .readdir = fuse_readdir, + .open = fuse_dir_open, + .release = fuse_dir_release, +}; + +static struct inode_operations fuse_common_inode_operations = { + .permission = fuse_permission, + .getattr = fuse_getattr, +}; + +static struct inode_operations fuse_symlink_inode_operations = { + .follow_link = fuse_follow_link, + .put_link = fuse_put_link, + .readlink = generic_readlink, + .getattr = fuse_getattr, +}; + +void fuse_init_common(struct inode *inode) +{ + inode->i_op = &fuse_common_inode_operations; +} + +void fuse_init_dir(struct inode *inode) +{ + inode->i_op = &fuse_dir_inode_operations; + inode->i_fop = &fuse_dir_operations; +} + +void fuse_init_symlink(struct inode *inode) +{ + inode->i_op = &fuse_symlink_inode_operations; +} diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 50ad6a0c39bfa..8d91e1492f964 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -30,6 +30,9 @@ struct fuse_inode { * and kernel */ u64 nodeid; + /** The request used for sending the FORGET message */ + struct fuse_req *forget_req; + /** Time in jiffies until the file attributes are valid */ unsigned long i_time; }; @@ -129,6 +132,7 @@ struct fuse_req { /** Data for asynchronous requests */ union { + struct fuse_forget_in forget_in; struct fuse_init_in_out init_in_out; } misc; @@ -197,6 +201,11 @@ struct fuse_conn { struct backing_dev_info bdi; }; +struct fuse_getdir_out_i { + int fd; + void *file; /* Used by kernel only */ +}; + static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb) { return (struct fuse_conn **) &sb->s_fs_info; @@ -239,6 +248,38 @@ extern struct file_operations fuse_dev_operations; */ extern spinlock_t fuse_lock; +/** + * Get a filled in inode + */ +struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, + int generation, struct fuse_attr *attr, int version); + +/** + * Send FORGET command + */ +void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, + unsigned long nodeid, int version); + +/** + * Initialise inode operations on regular files and special files + */ +void fuse_init_common(struct inode *inode); + +/** + * Initialise inode and file operations on a directory + */ +void fuse_init_dir(struct inode *inode); + +/** + * Initialise inode operations on a symlink + */ +void fuse_init_symlink(struct inode *inode); + +/** + * Change attributes of an inode + */ +void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr); + /** * Check if the connection can be released, and if yes, then free the * connection structure @@ -306,6 +347,16 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); */ void request_send_background(struct fuse_conn *fc, struct fuse_req *req); +/** + * Get the attributes of a file + */ +int fuse_do_getattr(struct inode *inode); + +/** + * Invalidate inode attributes + */ +void fuse_invalidate_attr(struct inode *inode); + /** * Send the INIT message */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 33fad334ba70e..41498a1952a07 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -51,12 +51,20 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) fi = get_fuse_inode(inode); fi->i_time = jiffies - 1; fi->nodeid = 0; + fi->forget_req = fuse_request_alloc(); + if (!fi->forget_req) { + kmem_cache_free(fuse_inode_cachep, inode); + return NULL; + } return inode; } static void fuse_destroy_inode(struct inode *inode) { + struct fuse_inode *fi = get_fuse_inode(inode); + if (fi->forget_req) + fuse_request_free(fi->forget_req); kmem_cache_free(fuse_inode_cachep, inode); } @@ -65,8 +73,27 @@ static void fuse_read_inode(struct inode *inode) /* No op */ } +void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, + unsigned long nodeid, int version) +{ + struct fuse_forget_in *inarg = &req->misc.forget_in; + inarg->version = version; + req->in.h.opcode = FUSE_FORGET; + req->in.h.nodeid = nodeid; + req->in.numargs = 1; + req->in.args[0].size = sizeof(struct fuse_forget_in); + req->in.args[0].value = inarg; + request_send_noreply(fc, req); +} + static void fuse_clear_inode(struct inode *inode) { + struct fuse_conn *fc = get_fuse_conn(inode); + if (fc) { + struct fuse_inode *fi = get_fuse_inode(inode); + fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version); + fi->forget_req = NULL; + } } void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) @@ -94,6 +121,22 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) { inode->i_mode = attr->mode & S_IFMT; i_size_write(inode, attr->size); + if (S_ISREG(inode->i_mode)) { + fuse_init_common(inode); + } else if (S_ISDIR(inode->i_mode)) + fuse_init_dir(inode); + else if (S_ISLNK(inode->i_mode)) + fuse_init_symlink(inode); + else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || + S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { + fuse_init_common(inode); + init_special_inode(inode, inode->i_mode, + new_decode_dev(attr->rdev)); + } else { + /* Don't let user create weird files */ + inode->i_mode = S_IFREG; + fuse_init_common(inode); + } } static int fuse_inode_eq(struct inode *inode, void *_nodeidp) @@ -158,6 +201,43 @@ static void fuse_put_super(struct super_block *sb) spin_unlock(&fuse_lock); } +static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) +{ + stbuf->f_type = FUSE_SUPER_MAGIC; + stbuf->f_bsize = attr->bsize; + stbuf->f_blocks = attr->blocks; + stbuf->f_bfree = attr->bfree; + stbuf->f_bavail = attr->bavail; + stbuf->f_files = attr->files; + stbuf->f_ffree = attr->ffree; + stbuf->f_namelen = attr->namelen; + /* fsid is left zero */ +} + +static int fuse_statfs(struct super_block *sb, struct kstatfs *buf) +{ + struct fuse_conn *fc = get_fuse_conn_super(sb); + struct fuse_req *req; + struct fuse_statfs_out outarg; + int err; + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + + req->in.numargs = 0; + req->in.h.opcode = FUSE_STATFS; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + if (!err) + convert_fuse_statfs(buf, &outarg.st); + fuse_put_request(fc, req); + return err; +} + enum { OPT_FD, OPT_ROOTMODE, @@ -318,6 +398,7 @@ static struct super_operations fuse_super_operations = { .read_inode = fuse_read_inode, .clear_inode = fuse_clear_inode, .put_super = fuse_put_super, + .statfs = fuse_statfs, .show_options = fuse_show_options, }; diff --git a/include/linux/fuse.h b/include/linux/fuse.h index a1aebd7104c42..21b9ba16f8d52 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -42,13 +42,61 @@ struct fuse_attr { __u32 rdev; }; +struct fuse_kstatfs { + __u64 blocks; + __u64 bfree; + __u64 bavail; + __u64 files; + __u64 ffree; + __u32 bsize; + __u32 namelen; +}; + enum fuse_opcode { + FUSE_LOOKUP = 1, + FUSE_FORGET = 2, /* no reply */ + FUSE_GETATTR = 3, + FUSE_READLINK = 5, + FUSE_GETDIR = 7, + FUSE_STATFS = 17, FUSE_INIT = 26 }; /* Conservative buffer size for the client */ #define FUSE_MAX_IN 8192 +#define FUSE_NAME_MAX 1024 + +struct fuse_entry_out { + __u64 nodeid; /* Inode ID */ + __u64 generation; /* Inode generation: nodeid:gen must + be unique for the fs's lifetime */ + __u64 entry_valid; /* Cache timeout for the name */ + __u64 attr_valid; /* Cache timeout for the attributes */ + __u32 entry_valid_nsec; + __u32 attr_valid_nsec; + struct fuse_attr attr; +}; + +struct fuse_forget_in { + __u64 version; +}; + +struct fuse_attr_out { + __u64 attr_valid; /* Cache timeout for the attributes */ + __u32 attr_valid_nsec; + __u32 dummy; + struct fuse_attr attr; +}; + +struct fuse_getdir_out { + __u32 fd; +}; + +struct fuse_statfs_out { + struct fuse_kstatfs st; +}; + struct fuse_init_in_out { __u32 major; __u32 minor; @@ -70,3 +118,15 @@ struct fuse_out_header { __u64 unique; }; +struct fuse_dirent { + __u64 ino; + __u64 off; + __u32 namelen; + __u32 type; + char name[0]; +}; + +#define FUSE_NAME_OFFSET ((unsigned) ((struct fuse_dirent *) 0)->name) +#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1)) +#define FUSE_DIRENT_SIZE(d) \ + FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) -- GitLab From 9e6268db496a2592e89457537ea54a496feabb77 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:29 -0700 Subject: [PATCH 267/563] [PATCH] FUSE - read-write operations This patch adds the write filesystem operations of FUSE. The following operations are added: o setattr o symlink o mknod o mkdir o create o unlink o rmdir o rename o link Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/dir.c | 373 +++++++++++++++++++++++++++++++++++++++++-- fs/fuse/fuse_i.h | 7 +- fs/fuse/inode.c | 15 +- include/linux/fuse.h | 43 ++++- 4 files changed, 419 insertions(+), 19 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index a89730e70c587..92c7188ccd16f 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -42,7 +42,6 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) return 0; else if (time_after(jiffies, entry->d_time)) { int err; - int version; struct fuse_entry_out outarg; struct inode *inode = entry->d_inode; struct fuse_inode *fi = get_fuse_inode(inode); @@ -53,15 +52,19 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); request_send_nonint(fc, req); - version = req->out.h.unique; err = req->out.h.error; + if (!err) { + if (outarg.nodeid != get_node_id(inode)) { + fuse_send_forget(fc, req, outarg.nodeid, 1); + return 0; + } + fi->nlookup ++; + } fuse_put_request(fc, req); - if (err || outarg.nodeid != get_node_id(inode) || - (outarg.attr.mode ^ inode->i_mode) & S_IFMT) + if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) return 0; fuse_change_attributes(inode, &outarg.attr); - inode->i_version = version; entry->d_time = time_to_jiffies(outarg.entry_valid, outarg.entry_valid_nsec); fi->i_time = time_to_jiffies(outarg.attr_valid, @@ -78,7 +81,6 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry, struct inode **inodep) { int err; - int version; struct fuse_entry_out outarg; struct inode *inode = NULL; struct fuse_conn *fc = get_fuse_conn(dir); @@ -93,13 +95,12 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry, fuse_lookup_init(req, dir, entry, &outarg); request_send(fc, req); - version = req->out.h.unique; err = req->out.h.error; if (!err) { inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, - &outarg.attr, version); + &outarg.attr); if (!inode) { - fuse_send_forget(fc, req, outarg.nodeid, version); + fuse_send_forget(fc, req, outarg.nodeid, 1); return -ENOMEM; } } @@ -120,6 +121,264 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry, return 0; } +void fuse_invalidate_attr(struct inode *inode) +{ + get_fuse_inode(inode)->i_time = jiffies - 1; +} + +static void fuse_invalidate_entry(struct dentry *entry) +{ + d_invalidate(entry); + entry->d_time = jiffies - 1; +} + +static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, + struct inode *dir, struct dentry *entry, + int mode) +{ + struct fuse_entry_out outarg; + struct inode *inode; + struct fuse_inode *fi; + int err; + + req->in.h.nodeid = get_node_id(dir); + req->inode = dir; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + if (err) { + fuse_put_request(fc, req); + return err; + } + inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, + &outarg.attr); + if (!inode) { + fuse_send_forget(fc, req, outarg.nodeid, 1); + return -ENOMEM; + } + fuse_put_request(fc, req); + + /* Don't allow userspace to do really stupid things... */ + if ((inode->i_mode ^ mode) & S_IFMT) { + iput(inode); + return -EIO; + } + + entry->d_time = time_to_jiffies(outarg.entry_valid, + outarg.entry_valid_nsec); + + fi = get_fuse_inode(inode); + fi->i_time = time_to_jiffies(outarg.attr_valid, + outarg.attr_valid_nsec); + + d_instantiate(entry, inode); + fuse_invalidate_attr(dir); + return 0; +} + +static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, + dev_t rdev) +{ + struct fuse_mknod_in inarg; + struct fuse_conn *fc = get_fuse_conn(dir); + struct fuse_req *req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.mode = mode; + inarg.rdev = new_encode_dev(rdev); + req->in.h.opcode = FUSE_MKNOD; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = entry->d_name.len + 1; + req->in.args[1].value = entry->d_name.name; + return create_new_entry(fc, req, dir, entry, mode); +} + +static int fuse_create(struct inode *dir, struct dentry *entry, int mode, + struct nameidata *nd) +{ + return fuse_mknod(dir, entry, mode, 0); +} + +static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) +{ + struct fuse_mkdir_in inarg; + struct fuse_conn *fc = get_fuse_conn(dir); + struct fuse_req *req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.mode = mode; + req->in.h.opcode = FUSE_MKDIR; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = entry->d_name.len + 1; + req->in.args[1].value = entry->d_name.name; + return create_new_entry(fc, req, dir, entry, S_IFDIR); +} + +static int fuse_symlink(struct inode *dir, struct dentry *entry, + const char *link) +{ + struct fuse_conn *fc = get_fuse_conn(dir); + unsigned len = strlen(link) + 1; + struct fuse_req *req; + + if (len > FUSE_SYMLINK_MAX) + return -ENAMETOOLONG; + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + req->in.h.opcode = FUSE_SYMLINK; + req->in.numargs = 2; + req->in.args[0].size = entry->d_name.len + 1; + req->in.args[0].value = entry->d_name.name; + req->in.args[1].size = len; + req->in.args[1].value = link; + return create_new_entry(fc, req, dir, entry, S_IFLNK); +} + +static int fuse_unlink(struct inode *dir, struct dentry *entry) +{ + int err; + struct fuse_conn *fc = get_fuse_conn(dir); + struct fuse_req *req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + req->in.h.opcode = FUSE_UNLINK; + req->in.h.nodeid = get_node_id(dir); + req->inode = dir; + req->in.numargs = 1; + req->in.args[0].size = entry->d_name.len + 1; + req->in.args[0].value = entry->d_name.name; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (!err) { + struct inode *inode = entry->d_inode; + + /* Set nlink to zero so the inode can be cleared, if + the inode does have more links this will be + discovered at the next lookup/getattr */ + inode->i_nlink = 0; + fuse_invalidate_attr(inode); + fuse_invalidate_attr(dir); + } else if (err == -EINTR) + fuse_invalidate_entry(entry); + return err; +} + +static int fuse_rmdir(struct inode *dir, struct dentry *entry) +{ + int err; + struct fuse_conn *fc = get_fuse_conn(dir); + struct fuse_req *req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + req->in.h.opcode = FUSE_RMDIR; + req->in.h.nodeid = get_node_id(dir); + req->inode = dir; + req->in.numargs = 1; + req->in.args[0].size = entry->d_name.len + 1; + req->in.args[0].value = entry->d_name.name; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (!err) { + entry->d_inode->i_nlink = 0; + fuse_invalidate_attr(dir); + } else if (err == -EINTR) + fuse_invalidate_entry(entry); + return err; +} + +static int fuse_rename(struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent) +{ + int err; + struct fuse_rename_in inarg; + struct fuse_conn *fc = get_fuse_conn(olddir); + struct fuse_req *req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.newdir = get_node_id(newdir); + req->in.h.opcode = FUSE_RENAME; + req->in.h.nodeid = get_node_id(olddir); + req->inode = olddir; + req->inode2 = newdir; + req->in.numargs = 3; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = oldent->d_name.len + 1; + req->in.args[1].value = oldent->d_name.name; + req->in.args[2].size = newent->d_name.len + 1; + req->in.args[2].value = newent->d_name.name; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (!err) { + fuse_invalidate_attr(olddir); + if (olddir != newdir) + fuse_invalidate_attr(newdir); + } else if (err == -EINTR) { + /* If request was interrupted, DEITY only knows if the + rename actually took place. If the invalidation + fails (e.g. some process has CWD under the renamed + directory), then there can be inconsistency between + the dcache and the real filesystem. Tough luck. */ + fuse_invalidate_entry(oldent); + if (newent->d_inode) + fuse_invalidate_entry(newent); + } + + return err; +} + +static int fuse_link(struct dentry *entry, struct inode *newdir, + struct dentry *newent) +{ + int err; + struct fuse_link_in inarg; + struct inode *inode = entry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.oldnodeid = get_node_id(inode); + req->in.h.opcode = FUSE_LINK; + req->inode2 = inode; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = newent->d_name.len + 1; + req->in.args[1].value = newent->d_name.name; + err = create_new_entry(fc, req, newdir, newent, inode->i_mode); + /* Contrary to "normal" filesystems it can happen that link + makes two "logical" inodes point to the same "physical" + inode. We invalidate the attributes of the old one, so it + will reflect changes in the backing inode (link count, + etc.) + */ + if (!err || err == -EINTR) + fuse_invalidate_attr(inode); + return err; +} + int fuse_do_getattr(struct inode *inode) { int err; @@ -341,6 +600,91 @@ static int fuse_dir_release(struct inode *inode, struct file *file) return 0; } +static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) +{ + unsigned ivalid = iattr->ia_valid; + unsigned fvalid = 0; + + memset(fattr, 0, sizeof(*fattr)); + + if (ivalid & ATTR_MODE) + fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode; + if (ivalid & ATTR_UID) + fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid; + if (ivalid & ATTR_GID) + fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid; + if (ivalid & ATTR_SIZE) + fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size; + /* You can only _set_ these together (they may change by themselves) */ + if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { + fvalid |= FATTR_ATIME | FATTR_MTIME; + fattr->atime = iattr->ia_atime.tv_sec; + fattr->mtime = iattr->ia_mtime.tv_sec; + } + + return fvalid; +} + +static int fuse_setattr(struct dentry *entry, struct iattr *attr) +{ + struct inode *inode = entry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_inode *fi = get_fuse_inode(inode); + struct fuse_req *req; + struct fuse_setattr_in inarg; + struct fuse_attr_out outarg; + int err; + int is_truncate = 0; + + if (attr->ia_valid & ATTR_SIZE) { + unsigned long limit; + is_truncate = 1; + limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; + if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { + send_sig(SIGXFSZ, current, 0); + return -EFBIG; + } + } + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.valid = iattr_to_fattr(attr, &inarg.attr); + req->in.h.opcode = FUSE_SETATTR; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (!err) { + if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { + make_bad_inode(inode); + err = -EIO; + } else { + if (is_truncate) { + loff_t origsize = i_size_read(inode); + i_size_write(inode, outarg.attr.size); + if (origsize > outarg.attr.size) + vmtruncate(inode, outarg.attr.size); + } + fuse_change_attributes(inode, &outarg.attr); + fi->i_time = time_to_jiffies(outarg.attr_valid, + outarg.attr_valid_nsec); + } + } else if (err == -EINTR) + fuse_invalidate_attr(inode); + + return err; +} + static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, struct kstat *stat) { @@ -373,6 +717,15 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, static struct inode_operations fuse_dir_inode_operations = { .lookup = fuse_lookup, + .mkdir = fuse_mkdir, + .symlink = fuse_symlink, + .unlink = fuse_unlink, + .rmdir = fuse_rmdir, + .rename = fuse_rename, + .link = fuse_link, + .setattr = fuse_setattr, + .create = fuse_create, + .mknod = fuse_mknod, .permission = fuse_permission, .getattr = fuse_getattr, }; @@ -385,11 +738,13 @@ static struct file_operations fuse_dir_operations = { }; static struct inode_operations fuse_common_inode_operations = { + .setattr = fuse_setattr, .permission = fuse_permission, .getattr = fuse_getattr, }; static struct inode_operations fuse_symlink_inode_operations = { + .setattr = fuse_setattr, .follow_link = fuse_follow_link, .put_link = fuse_put_link, .readlink = generic_readlink, diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 8d91e1492f964..87d25b8f2dc18 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -30,6 +30,9 @@ struct fuse_inode { * and kernel */ u64 nodeid; + /** Number of lookups on this inode */ + u64 nlookup; + /** The request used for sending the FORGET message */ struct fuse_req *forget_req; @@ -252,13 +255,13 @@ extern spinlock_t fuse_lock; * Get a filled in inode */ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, - int generation, struct fuse_attr *attr, int version); + int generation, struct fuse_attr *attr); /** * Send FORGET command */ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, - unsigned long nodeid, int version); + unsigned long nodeid, u64 nlookup); /** * Initialise inode operations on regular files and special files diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 41498a1952a07..fa03f80806e5d 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -51,6 +51,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) fi = get_fuse_inode(inode); fi->i_time = jiffies - 1; fi->nodeid = 0; + fi->nlookup = 0; fi->forget_req = fuse_request_alloc(); if (!fi->forget_req) { kmem_cache_free(fuse_inode_cachep, inode); @@ -74,10 +75,10 @@ static void fuse_read_inode(struct inode *inode) } void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, - unsigned long nodeid, int version) + unsigned long nodeid, u64 nlookup) { struct fuse_forget_in *inarg = &req->misc.forget_in; - inarg->version = version; + inarg->nlookup = nlookup; req->in.h.opcode = FUSE_FORGET; req->in.h.nodeid = nodeid; req->in.numargs = 1; @@ -91,7 +92,7 @@ static void fuse_clear_inode(struct inode *inode) struct fuse_conn *fc = get_fuse_conn(inode); if (fc) { struct fuse_inode *fi = get_fuse_inode(inode); - fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version); + fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); fi->forget_req = NULL; } } @@ -156,9 +157,10 @@ static int fuse_inode_set(struct inode *inode, void *_nodeidp) } struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, - int generation, struct fuse_attr *attr, int version) + int generation, struct fuse_attr *attr) { struct inode *inode; + struct fuse_inode *fi; struct fuse_conn *fc = get_fuse_conn_super(sb); int retried = 0; @@ -181,8 +183,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, goto retry; } + fi = get_fuse_inode(inode); + fi->nlookup ++; fuse_change_attributes(inode, attr); - inode->i_version = version; return inode; } @@ -389,7 +392,7 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode) attr.mode = mode; attr.ino = FUSE_ROOT_ID; - return fuse_iget(sb, 1, 0, &attr, 0); + return fuse_iget(sb, 1, 0, &attr); } static struct super_operations fuse_super_operations = { diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 21b9ba16f8d52..19d69a3e16238 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -11,7 +11,7 @@ #include <asm/types.h> /** Version number of this interface */ -#define FUSE_KERNEL_VERSION 6 +#define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ #define FUSE_KERNEL_MINOR_VERSION 1 @@ -52,12 +52,28 @@ struct fuse_kstatfs { __u32 namelen; }; +#define FATTR_MODE (1 << 0) +#define FATTR_UID (1 << 1) +#define FATTR_GID (1 << 2) +#define FATTR_SIZE (1 << 3) +#define FATTR_ATIME (1 << 4) +#define FATTR_MTIME (1 << 5) +#define FATTR_CTIME (1 << 6) + enum fuse_opcode { FUSE_LOOKUP = 1, FUSE_FORGET = 2, /* no reply */ FUSE_GETATTR = 3, + FUSE_SETATTR = 4, FUSE_READLINK = 5, + FUSE_SYMLINK = 6, FUSE_GETDIR = 7, + FUSE_MKNOD = 8, + FUSE_MKDIR = 9, + FUSE_UNLINK = 10, + FUSE_RMDIR = 11, + FUSE_RENAME = 12, + FUSE_LINK = 13, FUSE_STATFS = 17, FUSE_INIT = 26 }; @@ -66,6 +82,7 @@ enum fuse_opcode { #define FUSE_MAX_IN 8192 #define FUSE_NAME_MAX 1024 +#define FUSE_SYMLINK_MAX 4096 struct fuse_entry_out { __u64 nodeid; /* Inode ID */ @@ -79,7 +96,7 @@ struct fuse_entry_out { }; struct fuse_forget_in { - __u64 version; + __u64 nlookup; }; struct fuse_attr_out { @@ -93,6 +110,28 @@ struct fuse_getdir_out { __u32 fd; }; +struct fuse_mknod_in { + __u32 mode; + __u32 rdev; +}; + +struct fuse_mkdir_in { + __u32 mode; +}; + +struct fuse_rename_in { + __u64 newdir; +}; + +struct fuse_link_in { + __u64 oldnodeid; +}; + +struct fuse_setattr_in { + __u32 valid; + struct fuse_attr attr; +}; + struct fuse_statfs_out { struct fuse_kstatfs st; }; -- GitLab From b6aeadeda22a9aa322fdfcd3f4c69ccf0da5cbdd Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:30 -0700 Subject: [PATCH 268/563] [PATCH] FUSE - file operations This patch adds the file operations of FUSE. The following operations are added: o open o flush o release o fsync o readpage o commit_write Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/Makefile | 2 +- fs/fuse/dir.c | 1 + fs/fuse/file.c | 341 +++++++++++++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 21 +++ fs/fuse/inode.c | 2 + include/linux/fuse.h | 47 ++++++ 6 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 fs/fuse/file.c diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index c34e268a0ed34..c3e1f760cac9b 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_FUSE_FS) += fuse.o -fuse-objs := dev.o dir.o inode.o +fuse-objs := dev.o dir.o file.o inode.o diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 92c7188ccd16f..8adc1eed164b5 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -731,6 +731,7 @@ static struct inode_operations fuse_dir_inode_operations = { }; static struct file_operations fuse_dir_operations = { + .llseek = generic_file_llseek, .read = generic_read_dir, .readdir = fuse_readdir, .open = fuse_dir_open, diff --git a/fs/fuse/file.c b/fs/fuse/file.c new file mode 100644 index 0000000000000..de8c9c702461c --- /dev/null +++ b/fs/fuse/file.c @@ -0,0 +1,341 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include "fuse_i.h" + +#include <linux/pagemap.h> +#include <linux/slab.h> +#include <linux/kernel.h> + +static int fuse_open(struct inode *inode, struct file *file) +{ + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + struct fuse_open_in inarg; + struct fuse_open_out outarg; + struct fuse_file *ff; + int err; + /* Restarting the syscall is not allowed if O_CREAT and O_EXCL + are both set, because creation will fail on the restart */ + int excl = (file->f_flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL); + + err = generic_file_open(inode, file); + if (err) + return err; + + /* If opening the root node, no lookup has been performed on + it, so the attributes must be refreshed */ + if (get_node_id(inode) == FUSE_ROOT_ID) { + int err = fuse_do_getattr(inode); + if (err) + return err; + } + + if (excl) + req = fuse_get_request_nonint(fc); + else + req = fuse_get_request(fc); + if (!req) + return excl ? -EINTR : -ERESTARTSYS; + + err = -ENOMEM; + ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL); + if (!ff) + goto out_put_request; + + ff->release_req = fuse_request_alloc(); + if (!ff->release_req) { + kfree(ff); + goto out_put_request; + } + + memset(&inarg, 0, sizeof(inarg)); + inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); + req->in.h.opcode = FUSE_OPEN; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + if (excl) + request_send_nonint(fc, req); + else + request_send(fc, req); + err = req->out.h.error; + if (!err) + invalidate_inode_pages(inode->i_mapping); + if (err) { + fuse_request_free(ff->release_req); + kfree(ff); + } else { + ff->fh = outarg.fh; + file->private_data = ff; + } + + out_put_request: + fuse_put_request(fc, req); + return err; +} + +static int fuse_release(struct inode *inode, struct file *file) +{ + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_file *ff = file->private_data; + struct fuse_req *req = ff->release_req; + struct fuse_release_in *inarg = &req->misc.release_in; + + inarg->fh = ff->fh; + inarg->flags = file->f_flags & ~O_EXCL; + req->in.h.opcode = FUSE_RELEASE; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 1; + req->in.args[0].size = sizeof(struct fuse_release_in); + req->in.args[0].value = inarg; + request_send_background(fc, req); + kfree(ff); + + /* Return value is ignored by VFS */ + return 0; +} + +static int fuse_flush(struct file *file) +{ + struct inode *inode = file->f_dentry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_file *ff = file->private_data; + struct fuse_req *req; + struct fuse_flush_in inarg; + int err; + + if (fc->no_flush) + return 0; + + req = fuse_get_request_nonint(fc); + if (!req) + return -EINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.fh = ff->fh; + req->in.h.opcode = FUSE_FLUSH; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->file = file; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + request_send_nonint(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (err == -ENOSYS) { + fc->no_flush = 1; + err = 0; + } + return err; +} + +static int fuse_fsync(struct file *file, struct dentry *de, int datasync) +{ + struct inode *inode = de->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_file *ff = file->private_data; + struct fuse_req *req; + struct fuse_fsync_in inarg; + int err; + + if (fc->no_fsync) + return 0; + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + + memset(&inarg, 0, sizeof(inarg)); + inarg.fh = ff->fh; + inarg.fsync_flags = datasync ? 1 : 0; + req->in.h.opcode = FUSE_FSYNC; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->file = file; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (err == -ENOSYS) { + fc->no_fsync = 1; + err = 0; + } + return err; +} + +static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count) +{ + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_file *ff = file->private_data; + struct fuse_read_in inarg; + + memset(&inarg, 0, sizeof(struct fuse_read_in)); + inarg.fh = ff->fh; + inarg.offset = pos; + inarg.size = count; + req->in.h.opcode = FUSE_READ; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->file = file; + req->in.numargs = 1; + req->in.args[0].size = sizeof(struct fuse_read_in); + req->in.args[0].value = &inarg; + req->out.argpages = 1; + req->out.argvar = 1; + req->out.numargs = 1; + req->out.args[0].size = count; + request_send_nonint(fc, req); + return req->out.args[0].size; +} + +static int fuse_readpage(struct file *file, struct page *page) +{ + struct inode *inode = page->mapping->host; + struct fuse_conn *fc = get_fuse_conn(inode); + loff_t pos = (loff_t) page->index << PAGE_CACHE_SHIFT; + struct fuse_req *req = fuse_get_request_nonint(fc); + int err = -EINTR; + if (!req) + goto out; + + req->out.page_zeroing = 1; + req->num_pages = 1; + req->pages[0] = page; + fuse_send_read(req, file, inode, pos, PAGE_CACHE_SIZE); + err = req->out.h.error; + fuse_put_request(fc, req); + if (!err) + SetPageUptodate(page); + out: + unlock_page(page); + return err; +} + +static ssize_t fuse_send_write(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count) +{ + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_file *ff = file->private_data; + struct fuse_write_in inarg; + struct fuse_write_out outarg; + + memset(&inarg, 0, sizeof(struct fuse_write_in)); + inarg.fh = ff->fh; + inarg.offset = pos; + inarg.size = count; + req->in.h.opcode = FUSE_WRITE; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->file = file; + req->in.argpages = 1; + req->in.numargs = 2; + req->in.args[0].size = sizeof(struct fuse_write_in); + req->in.args[0].value = &inarg; + req->in.args[1].size = count; + req->out.numargs = 1; + req->out.args[0].size = sizeof(struct fuse_write_out); + req->out.args[0].value = &outarg; + request_send_nonint(fc, req); + return outarg.size; +} + +static int fuse_prepare_write(struct file *file, struct page *page, + unsigned offset, unsigned to) +{ + /* No op */ + return 0; +} + +static int fuse_commit_write(struct file *file, struct page *page, + unsigned offset, unsigned to) +{ + int err; + ssize_t nres; + unsigned count = to - offset; + struct inode *inode = page->mapping->host; + struct fuse_conn *fc = get_fuse_conn(inode); + loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset; + struct fuse_req *req = fuse_get_request_nonint(fc); + if (!req) + return -EINTR; + + req->num_pages = 1; + req->pages[0] = page; + req->page_offset = offset; + nres = fuse_send_write(req, file, inode, pos, count); + err = req->out.h.error; + fuse_put_request(fc, req); + if (!err && nres != count) + err = -EIO; + if (!err) { + pos += count; + if (pos > i_size_read(inode)) + i_size_write(inode, pos); + + if (offset == 0 && to == PAGE_CACHE_SIZE) { + clear_page_dirty(page); + SetPageUptodate(page); + } + } else if (err == -EINTR || err == -EIO) + fuse_invalidate_attr(inode); + return err; +} + +static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + if ((vma->vm_flags & VM_SHARED)) { + if ((vma->vm_flags & VM_WRITE)) + return -ENODEV; + else + vma->vm_flags &= ~VM_MAYWRITE; + } + return generic_file_mmap(file, vma); +} + +static int fuse_set_page_dirty(struct page *page) +{ + printk("fuse_set_page_dirty: should not happen\n"); + dump_stack(); + return 0; +} + +static struct file_operations fuse_file_operations = { + .llseek = generic_file_llseek, + .read = generic_file_read, + .write = generic_file_write, + .mmap = fuse_file_mmap, + .open = fuse_open, + .flush = fuse_flush, + .release = fuse_release, + .fsync = fuse_fsync, + .sendfile = generic_file_sendfile, +}; + +static struct address_space_operations fuse_file_aops = { + .readpage = fuse_readpage, + .prepare_write = fuse_prepare_write, + .commit_write = fuse_commit_write, + .set_page_dirty = fuse_set_page_dirty, +}; + +void fuse_init_file_inode(struct inode *inode) +{ + inode->i_fop = &fuse_file_operations; + inode->i_data.a_ops = &fuse_file_aops; +} diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 87d25b8f2dc18..b4aa8f7bc2c10 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -40,6 +40,15 @@ struct fuse_inode { unsigned long i_time; }; +/** FUSE specific file data */ +struct fuse_file { + /** Request reserved for flush and release */ + struct fuse_req *release_req; + + /** File handle used by userspace */ + u64 fh; +}; + /** One input argument of a request */ struct fuse_in_arg { unsigned size; @@ -136,6 +145,7 @@ struct fuse_req { /** Data for asynchronous requests */ union { struct fuse_forget_in forget_in; + struct fuse_release_in release_in; struct fuse_init_in_out init_in_out; } misc; @@ -200,6 +210,12 @@ struct fuse_conn { /** Connection failed (version mismatch) */ unsigned conn_error : 1; + /** Is fsync not implemented by fs? */ + unsigned no_fsync : 1; + + /** Is flush not implemented by fs? */ + unsigned no_flush : 1; + /** Backing dev info */ struct backing_dev_info bdi; }; @@ -263,6 +279,11 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, unsigned long nodeid, u64 nlookup); +/** + * Initialise file operations on a regular file + */ +void fuse_init_file_inode(struct inode *inode); + /** * Initialise inode operations on regular files and special files */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index fa03f80806e5d..f229d6962643a 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -124,6 +124,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) i_size_write(inode, attr->size); if (S_ISREG(inode->i_mode)) { fuse_init_common(inode); + fuse_init_file_inode(inode); } else if (S_ISDIR(inode->i_mode)) fuse_init_dir(inode); else if (S_ISLNK(inode->i_mode)) @@ -137,6 +138,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) /* Don't let user create weird files */ inode->i_mode = S_IFREG; fuse_init_common(inode); + fuse_init_file_inode(inode); } } diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 19d69a3e16238..61f34636ffbcc 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -74,7 +74,13 @@ enum fuse_opcode { FUSE_RMDIR = 11, FUSE_RENAME = 12, FUSE_LINK = 13, + FUSE_OPEN = 14, + FUSE_READ = 15, + FUSE_WRITE = 16, FUSE_STATFS = 17, + FUSE_RELEASE = 18, + FUSE_FSYNC = 20, + FUSE_FLUSH = 25, FUSE_INIT = 26 }; @@ -132,10 +138,51 @@ struct fuse_setattr_in { struct fuse_attr attr; }; +struct fuse_open_in { + __u32 flags; +}; + +struct fuse_open_out { + __u64 fh; + __u32 open_flags; +}; + +struct fuse_release_in { + __u64 fh; + __u32 flags; +}; + +struct fuse_flush_in { + __u64 fh; + __u32 flush_flags; +}; + +struct fuse_read_in { + __u64 fh; + __u64 offset; + __u32 size; +}; + +struct fuse_write_in { + __u64 fh; + __u64 offset; + __u32 size; + __u32 write_flags; +}; + +struct fuse_write_out { + __u32 size; +}; + struct fuse_statfs_out { struct fuse_kstatfs st; }; +struct fuse_fsync_in { + __u64 fh; + __u32 fsync_flags; +}; + struct fuse_init_in_out { __u32 major; __u32 minor; -- GitLab From 1e9a4ed9396e9c31139721b639550ffb1df17065 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:31 -0700 Subject: [PATCH 269/563] [PATCH] FUSE - mount options This patch adds miscellaneous mount options to the FUSE filesystem. The following mount options are added: o default_permissions: check permissions with generic_permission() o allow_other: allow other users to access files o allow_root: allow root to access files o kernel_cache: don't invalidate page cache on open Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/dev.c | 78 ++++++++++++++++++++++++++++++++++++------------ fs/fuse/dir.c | 35 ++++++++++++++++++++-- fs/fuse/file.c | 2 +- fs/fuse/fuse_i.h | 45 ++++++++++++++++++++++++---- fs/fuse/inode.c | 77 +++++++++++++++++++++++------------------------ 5 files changed, 170 insertions(+), 67 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index e8f3170946f1f..ca6fc0e96d7c7 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -26,7 +26,7 @@ static inline struct fuse_conn *fuse_get_conn(struct file *file) struct fuse_conn *fc; spin_lock(&fuse_lock); fc = file->private_data; - if (fc && !fc->sb) + if (fc && !fc->mounted) fc = NULL; spin_unlock(&fuse_lock); return fc; @@ -148,6 +148,17 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) fuse_putback_request(fc, req); } +void fuse_release_background(struct fuse_req *req) +{ + iput(req->inode); + iput(req->inode2); + if (req->file) + fput(req->file); + spin_lock(&fuse_lock); + list_del(&req->bg_entry); + spin_unlock(&fuse_lock); +} + /* * This function is called when a request is finished. Either a reply * has arrived or it was interrupted (and not yet sent) or some error @@ -166,12 +177,10 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) putback = atomic_dec_and_test(&req->count); spin_unlock(&fuse_lock); if (req->background) { - if (req->inode) - iput(req->inode); - if (req->inode2) - iput(req->inode2); - if (req->file) - fput(req->file); + down_read(&fc->sbput_sem); + if (fc->mounted) + fuse_release_background(req); + up_read(&fc->sbput_sem); } wake_up(&req->waitq); if (req->in.h.opcode == FUSE_INIT) { @@ -191,11 +200,39 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) fuse_putback_request(fc, req); } -static void background_request(struct fuse_req *req) +/* + * Unfortunately request interruption not just solves the deadlock + * problem, it causes problems too. These stem from the fact, that an + * interrupted request is continued to be processed in userspace, + * while all the locks and object references (inode and file) held + * during the operation are released. + * + * To release the locks is exactly why there's a need to interrupt the + * request, so there's not a lot that can be done about this, except + * introduce additional locking in userspace. + * + * More important is to keep inode and file references until userspace + * has replied, otherwise FORGET and RELEASE could be sent while the + * inode/file is still used by the filesystem. + * + * For this reason the concept of "background" request is introduced. + * An interrupted request is backgrounded if it has been already sent + * to userspace. Backgrounding involves getting an extra reference to + * inode(s) or file used in the request, and adding the request to + * fc->background list. When a reply is received for a background + * request, the object references are released, and the request is + * removed from the list. If the filesystem is unmounted while there + * are still background requests, the list is walked and references + * are released as if a reply was received. + * + * There's one more use for a background request. The RELEASE message is + * always sent as background, since it doesn't return an error or + * data. + */ +static void background_request(struct fuse_conn *fc, struct fuse_req *req) { - /* Need to get hold of the inode(s) and/or file used in the - request, so FORGET and RELEASE are not sent too early */ req->background = 1; + list_add(&req->bg_entry, &fc->background); if (req->inode) req->inode = igrab(req->inode); if (req->inode2) @@ -215,7 +252,8 @@ static int request_wait_answer_nonint(struct fuse_req *req) } /* Called with fuse_lock held. Releases, and then reacquires it. */ -static void request_wait_answer(struct fuse_req *req, int interruptible) +static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req, + int interruptible) { int intr; @@ -255,7 +293,7 @@ static void request_wait_answer(struct fuse_req *req, int interruptible) list_del(&req->list); __fuse_put_request(req); } else if (!req->finished && req->sent) - background_request(req); + background_request(fc, req); } static unsigned len_args(unsigned numargs, struct fuse_arg *args) @@ -297,7 +335,7 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req, { req->isreply = 1; spin_lock(&fuse_lock); - if (!fc->file) + if (!fc->connected) req->out.h.error = -ENOTCONN; else if (fc->conn_error) req->out.h.error = -ECONNREFUSED; @@ -307,7 +345,7 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req, after request_end() */ __fuse_get_request(req); - request_wait_answer(req, interruptible); + request_wait_answer(fc, req, interruptible); } spin_unlock(&fuse_lock); } @@ -330,7 +368,7 @@ void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req) static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) { spin_lock(&fuse_lock); - if (fc->file) { + if (fc->connected) { queue_request(fc, req); spin_unlock(&fuse_lock); } else { @@ -348,7 +386,9 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) void request_send_background(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 1; - background_request(req); + spin_lock(&fuse_lock); + background_request(fc, req); + spin_unlock(&fuse_lock); request_send_nowait(fc, req); } @@ -583,7 +623,7 @@ static void request_wait(struct fuse_conn *fc) DECLARE_WAITQUEUE(wait, current); add_wait_queue_exclusive(&fc->waitq, &wait); - while (fc->sb && list_empty(&fc->pending)) { + while (fc->mounted && list_empty(&fc->pending)) { set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) break; @@ -622,7 +662,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov, goto err_unlock; request_wait(fc); err = -ENODEV; - if (!fc->sb) + if (!fc->mounted) goto err_unlock; err = -ERESTARTSYS; if (list_empty(&fc->pending)) @@ -839,7 +879,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file) spin_lock(&fuse_lock); fc = file->private_data; if (fc) { - fc->file = NULL; + fc->connected = 0; end_requests(fc, &fc->pending); end_requests(fc, &fc->processing); fuse_release_conn(fc); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 8adc1eed164b5..0950455914dd6 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -418,7 +418,8 @@ static int fuse_revalidate(struct dentry *entry) struct fuse_conn *fc = get_fuse_conn(inode); if (get_node_id(inode) == FUSE_ROOT_ID) { - if (current->fsuid != fc->user_id) + if (!(fc->flags & FUSE_ALLOW_OTHER) && + current->fsuid != fc->user_id) return -EACCES; } else if (time_before_eq(jiffies, fi->i_time)) return 0; @@ -430,9 +431,31 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) { struct fuse_conn *fc = get_fuse_conn(inode); - if (current->fsuid != fc->user_id) + if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->user_id) return -EACCES; - else { + else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { + int err = generic_permission(inode, mask, NULL); + + /* If permission is denied, try to refresh file + attributes. This is also needed, because the root + node will at first have no permissions */ + if (err == -EACCES) { + err = fuse_do_getattr(inode); + if (!err) + err = generic_permission(inode, mask, NULL); + } + + /* FIXME: Need some mechanism to revoke permissions: + currently if the filesystem suddenly changes the + file mode, we will not be informed about it, and + continue to allow access to the file/directory. + + This is actually not so grave, since the user can + simply keep access to the file/directory anyway by + keeping it open... */ + + return err; + } else { int mode = inode->i_mode; if ((mask & MAY_WRITE) && IS_RDONLY(inode) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) @@ -636,6 +659,12 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) int err; int is_truncate = 0; + if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { + err = inode_change_ok(inode, attr); + if (err) + return err; + } + if (attr->ia_valid & ATTR_SIZE) { unsigned long limit; is_truncate = 1; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index de8c9c702461c..96ea302db184b 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -70,7 +70,7 @@ static int fuse_open(struct inode *inode, struct file *file) else request_send(fc, req); err = req->out.h.error; - if (!err) + if (!err && !(fc->flags & FUSE_KERNEL_CACHE)) invalidate_inode_pages(inode->i_mapping); if (err) { fuse_request_free(ff->release_req); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index b4aa8f7bc2c10..c8e6c87496e0c 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -21,6 +21,19 @@ /** If more requests are outstanding, then the operation will block */ #define FUSE_MAX_OUTSTANDING 10 +/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem + module will check permissions based on the file mode. Otherwise no + permission checking is done in the kernel */ +#define FUSE_DEFAULT_PERMISSIONS (1 << 0) + +/** If the FUSE_ALLOW_OTHER flag is given, then not only the user + doing the mount will be allowed to access the filesystem */ +#define FUSE_ALLOW_OTHER (1 << 1) + +/** If the FUSE_KERNEL_CACHE flag is given, then cached data will not + be flushed on open */ +#define FUSE_KERNEL_CACHE (1 << 2) + /** FUSE inode */ struct fuse_inode { /** Inode data */ @@ -109,6 +122,9 @@ struct fuse_req { lists in fuse_conn */ struct list_head list; + /** Entry on the background list */ + struct list_head bg_entry; + /** refcount */ atomic_t count; @@ -176,15 +192,15 @@ struct fuse_req { * unmounted. */ struct fuse_conn { - /** The superblock of the mounted filesystem */ - struct super_block *sb; - - /** The opened client device */ - struct file *file; + /** Reference count */ + int count; /** The user id for this mount */ uid_t user_id; + /** The fuse mount flags for this mount */ + unsigned flags; + /** Readers of the connection are waiting on this */ wait_queue_head_t waitq; @@ -194,6 +210,10 @@ struct fuse_conn { /** The list of requests being processed */ struct list_head processing; + /** Requests put in the background (RELEASE or any other + interrupted request) */ + struct list_head background; + /** Controls the maximum number of outstanding requests */ struct semaphore outstanding_sem; @@ -201,12 +221,21 @@ struct fuse_conn { outstanding_sem would go negative */ unsigned outstanding_debt; + /** RW semaphore for exclusion with fuse_put_super() */ + struct rw_semaphore sbput_sem; + /** The list of unused requests */ struct list_head unused_list; /** The next unique request id */ u64 reqctr; + /** Mount is active */ + unsigned mounted : 1; + + /** Connection established */ + unsigned connected : 1; + /** Connection failed (version mismatch) */ unsigned conn_error : 1; @@ -261,6 +290,7 @@ extern struct file_operations fuse_dev_operations; * - the private_data field of the device file * - the s_fs_info field of the super block * - unused_list, pending, processing lists in fuse_conn + * - background list in fuse_conn * - the unique request ID counter reqctr in fuse_conn * - the sb (super_block) field in fuse_conn * - the file (device file) field in fuse_conn @@ -371,6 +401,11 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); */ void request_send_background(struct fuse_conn *fc, struct fuse_req *req); +/** + * Release inodes and file assiciated with background request + */ +void fuse_release_background(struct fuse_req *req); + /** * Get the attributes of a file */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index f229d6962643a..458c62ca0fec1 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -15,7 +15,6 @@ #include <linux/seq_file.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/parser.h> #include <linux/statfs.h> @@ -25,11 +24,6 @@ MODULE_LICENSE("GPL"); spinlock_t fuse_lock; static kmem_cache_t *fuse_inode_cachep; -static int mount_count; - -static int mount_max = 1000; -module_param(mount_max, int, 0644); -MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)"); #define FUSE_SUPER_MAGIC 0x65735546 @@ -37,6 +31,7 @@ struct fuse_mount_data { int fd; unsigned rootmode; unsigned user_id; + unsigned flags; }; static struct inode *fuse_alloc_inode(struct super_block *sb) @@ -89,8 +84,8 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, static void fuse_clear_inode(struct inode *inode) { - struct fuse_conn *fc = get_fuse_conn(inode); - if (fc) { + if (inode->i_sb->s_flags & MS_ACTIVE) { + struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_inode *fi = get_fuse_inode(inode); fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); fi->forget_req = NULL; @@ -195,14 +190,19 @@ static void fuse_put_super(struct super_block *sb) { struct fuse_conn *fc = get_fuse_conn_super(sb); + down_write(&fc->sbput_sem); + while (!list_empty(&fc->background)) + fuse_release_background(list_entry(fc->background.next, + struct fuse_req, bg_entry)); + spin_lock(&fuse_lock); - mount_count --; - fc->sb = NULL; + fc->mounted = 0; fc->user_id = 0; + fc->flags = 0; /* Flush all readers on this fs */ wake_up_all(&fc->waitq); + up_write(&fc->sbput_sem); fuse_release_conn(fc); - *get_fuse_conn_super_p(sb) = NULL; spin_unlock(&fuse_lock); } @@ -249,7 +249,6 @@ enum { OPT_USER_ID, OPT_DEFAULT_PERMISSIONS, OPT_ALLOW_OTHER, - OPT_ALLOW_ROOT, OPT_KERNEL_CACHE, OPT_ERR }; @@ -260,7 +259,6 @@ static match_table_t tokens = { {OPT_USER_ID, "user_id=%u"}, {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, {OPT_ALLOW_OTHER, "allow_other"}, - {OPT_ALLOW_ROOT, "allow_root"}, {OPT_KERNEL_CACHE, "kernel_cache"}, {OPT_ERR, NULL} }; @@ -298,6 +296,18 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) d->user_id = value; break; + case OPT_DEFAULT_PERMISSIONS: + d->flags |= FUSE_DEFAULT_PERMISSIONS; + break; + + case OPT_ALLOW_OTHER: + d->flags |= FUSE_ALLOW_OTHER; + break; + + case OPT_KERNEL_CACHE: + d->flags |= FUSE_KERNEL_CACHE; + break; + default: return 0; } @@ -313,6 +323,12 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); seq_printf(m, ",user_id=%u", fc->user_id); + if (fc->flags & FUSE_DEFAULT_PERMISSIONS) + seq_puts(m, ",default_permissions"); + if (fc->flags & FUSE_ALLOW_OTHER) + seq_puts(m, ",allow_other"); + if (fc->flags & FUSE_KERNEL_CACHE) + seq_puts(m, ",kernel_cache"); return 0; } @@ -330,7 +346,8 @@ static void free_conn(struct fuse_conn *fc) /* Must be called with the fuse lock held */ void fuse_release_conn(struct fuse_conn *fc) { - if (!fc->sb && !fc->file) + fc->count--; + if (!fc->count) free_conn(fc); } @@ -342,14 +359,13 @@ static struct fuse_conn *new_conn(void) if (fc != NULL) { int i; memset(fc, 0, sizeof(*fc)); - fc->sb = NULL; - fc->file = NULL; - fc->user_id = 0; init_waitqueue_head(&fc->waitq); INIT_LIST_HEAD(&fc->pending); INIT_LIST_HEAD(&fc->processing); INIT_LIST_HEAD(&fc->unused_list); + INIT_LIST_HEAD(&fc->background); sema_init(&fc->outstanding_sem, 0); + init_rwsem(&fc->sbput_sem); for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { struct fuse_req *req = fuse_request_alloc(); if (!req) { @@ -380,8 +396,10 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) fc = ERR_PTR(-EINVAL); } else { file->private_data = fc; - fc->sb = sb; - fc->file = file; + *get_fuse_conn_super_p(sb) = fc; + fc->mounted = 1; + fc->connected = 1; + fc->count = 2; } spin_unlock(&fuse_lock); return fc; @@ -407,17 +425,6 @@ static struct super_operations fuse_super_operations = { .show_options = fuse_show_options, }; -static int inc_mount_count(void) -{ - int success = 0; - spin_lock(&fuse_lock); - mount_count ++; - if (mount_max == -1 || mount_count <= mount_max) - success = 1; - spin_unlock(&fuse_lock); - return success; -} - static int fuse_fill_super(struct super_block *sb, void *data, int silent) { struct fuse_conn *fc; @@ -444,14 +451,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) if (IS_ERR(fc)) return PTR_ERR(fc); + fc->flags = d.flags; fc->user_id = d.user_id; - *get_fuse_conn_super_p(sb) = fc; - - err = -ENFILE; - if (!inc_mount_count() && current->uid != 0) - goto err; - err = -ENOMEM; root = get_root_inode(sb, d.rootmode); if (root == NULL) @@ -467,11 +469,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) err: spin_lock(&fuse_lock); - mount_count --; - fc->sb = NULL; fuse_release_conn(fc); spin_unlock(&fuse_lock); - *get_fuse_conn_super_p(sb) = NULL; return err; } -- GitLab From 92a8780e1136c5ca0c7ed940000d399943d1576e Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:31 -0700 Subject: [PATCH 270/563] [PATCH] FUSE - extended attribute operations This patch adds the extended attribute operations to FUSE. The following operations are added: o getxattr o setxattr o listxattr o removexattr Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/dir.c | 183 +++++++++++++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 12 +++ include/linux/fuse.h | 18 +++++ 3 files changed, 213 insertions(+) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 0950455914dd6..f127625543b4d 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -744,6 +744,177 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, return d_splice_alias(inode, entry); } +static int fuse_setxattr(struct dentry *entry, const char *name, + const void *value, size_t size, int flags) +{ + struct inode *inode = entry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + struct fuse_setxattr_in inarg; + int err; + + if (size > FUSE_XATTR_SIZE_MAX) + return -E2BIG; + + if (fc->no_setxattr) + return -EOPNOTSUPP; + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.size = size; + inarg.flags = flags; + req->in.h.opcode = FUSE_SETXATTR; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 3; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = strlen(name) + 1; + req->in.args[1].value = name; + req->in.args[2].size = size; + req->in.args[2].value = value; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (err == -ENOSYS) { + fc->no_setxattr = 1; + err = -EOPNOTSUPP; + } + return err; +} + +static ssize_t fuse_getxattr(struct dentry *entry, const char *name, + void *value, size_t size) +{ + struct inode *inode = entry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + struct fuse_getxattr_in inarg; + struct fuse_getxattr_out outarg; + ssize_t ret; + + if (fc->no_getxattr) + return -EOPNOTSUPP; + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.size = size; + req->in.h.opcode = FUSE_GETXATTR; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = strlen(name) + 1; + req->in.args[1].value = name; + /* This is really two different operations rolled into one */ + req->out.numargs = 1; + if (size) { + req->out.argvar = 1; + req->out.args[0].size = size; + req->out.args[0].value = value; + } else { + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + } + request_send(fc, req); + ret = req->out.h.error; + if (!ret) + ret = size ? req->out.args[0].size : outarg.size; + else { + if (ret == -ENOSYS) { + fc->no_getxattr = 1; + ret = -EOPNOTSUPP; + } + } + fuse_put_request(fc, req); + return ret; +} + +static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) +{ + struct inode *inode = entry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + struct fuse_getxattr_in inarg; + struct fuse_getxattr_out outarg; + ssize_t ret; + + if (fc->no_listxattr) + return -EOPNOTSUPP; + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.size = size; + req->in.h.opcode = FUSE_LISTXATTR; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + /* This is really two different operations rolled into one */ + req->out.numargs = 1; + if (size) { + req->out.argvar = 1; + req->out.args[0].size = size; + req->out.args[0].value = list; + } else { + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + } + request_send(fc, req); + ret = req->out.h.error; + if (!ret) + ret = size ? req->out.args[0].size : outarg.size; + else { + if (ret == -ENOSYS) { + fc->no_listxattr = 1; + ret = -EOPNOTSUPP; + } + } + fuse_put_request(fc, req); + return ret; +} + +static int fuse_removexattr(struct dentry *entry, const char *name) +{ + struct inode *inode = entry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + int err; + + if (fc->no_removexattr) + return -EOPNOTSUPP; + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTNOINTR; + + req->in.h.opcode = FUSE_REMOVEXATTR; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 1; + req->in.args[0].size = strlen(name) + 1; + req->in.args[0].value = name; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (err == -ENOSYS) { + fc->no_removexattr = 1; + err = -EOPNOTSUPP; + } + return err; +} + static struct inode_operations fuse_dir_inode_operations = { .lookup = fuse_lookup, .mkdir = fuse_mkdir, @@ -757,6 +928,10 @@ static struct inode_operations fuse_dir_inode_operations = { .mknod = fuse_mknod, .permission = fuse_permission, .getattr = fuse_getattr, + .setxattr = fuse_setxattr, + .getxattr = fuse_getxattr, + .listxattr = fuse_listxattr, + .removexattr = fuse_removexattr, }; static struct file_operations fuse_dir_operations = { @@ -771,6 +946,10 @@ static struct inode_operations fuse_common_inode_operations = { .setattr = fuse_setattr, .permission = fuse_permission, .getattr = fuse_getattr, + .setxattr = fuse_setxattr, + .getxattr = fuse_getxattr, + .listxattr = fuse_listxattr, + .removexattr = fuse_removexattr, }; static struct inode_operations fuse_symlink_inode_operations = { @@ -779,6 +958,10 @@ static struct inode_operations fuse_symlink_inode_operations = { .put_link = fuse_put_link, .readlink = generic_readlink, .getattr = fuse_getattr, + .setxattr = fuse_setxattr, + .getxattr = fuse_getxattr, + .listxattr = fuse_listxattr, + .removexattr = fuse_removexattr, }; void fuse_init_common(struct inode *inode) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index c8e6c87496e0c..86183c5621048 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -245,6 +245,18 @@ struct fuse_conn { /** Is flush not implemented by fs? */ unsigned no_flush : 1; + /** Is setxattr not implemented by fs? */ + unsigned no_setxattr : 1; + + /** Is getxattr not implemented by fs? */ + unsigned no_getxattr : 1; + + /** Is listxattr not implemented by fs? */ + unsigned no_listxattr : 1; + + /** Is removexattr not implemented by fs? */ + unsigned no_removexattr : 1; + /** Backing dev info */ struct backing_dev_info bdi; }; diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 61f34636ffbcc..bf564edf99054 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -80,6 +80,10 @@ enum fuse_opcode { FUSE_STATFS = 17, FUSE_RELEASE = 18, FUSE_FSYNC = 20, + FUSE_SETXATTR = 21, + FUSE_GETXATTR = 22, + FUSE_LISTXATTR = 23, + FUSE_REMOVEXATTR = 24, FUSE_FLUSH = 25, FUSE_INIT = 26 }; @@ -89,6 +93,7 @@ enum fuse_opcode { #define FUSE_NAME_MAX 1024 #define FUSE_SYMLINK_MAX 4096 +#define FUSE_XATTR_SIZE_MAX 4096 struct fuse_entry_out { __u64 nodeid; /* Inode ID */ @@ -183,6 +188,19 @@ struct fuse_fsync_in { __u32 fsync_flags; }; +struct fuse_setxattr_in { + __u32 size; + __u32 flags; +}; + +struct fuse_getxattr_in { + __u32 size; +}; + +struct fuse_getxattr_out { + __u32 size; +}; + struct fuse_init_in_out { __u32 major; __u32 minor; -- GitLab From 06663267b4b1e85ece73236ea720355668d4f736 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:32 -0700 Subject: [PATCH 271/563] [PATCH] FUSE: add padding Add padding to structures to make sizes the same on 32bit and 64bit archs. Initial testing and test machine generously provided by Franco Broi. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/fuse.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/linux/fuse.h b/include/linux/fuse.h index bf564edf99054..e9b814e16c586 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -25,6 +25,9 @@ /** The minor number of the fuse character device */ #define FUSE_MINOR 229 +/* Make sure all structures are padded to 64bit boundary, so 32bit + userspace works under 64bit kernels */ + struct fuse_attr { __u64 ino; __u64 size; @@ -128,6 +131,7 @@ struct fuse_mknod_in { struct fuse_mkdir_in { __u32 mode; + __u32 padding; }; struct fuse_rename_in { @@ -140,32 +144,38 @@ struct fuse_link_in { struct fuse_setattr_in { __u32 valid; + __u32 padding; struct fuse_attr attr; }; struct fuse_open_in { __u32 flags; + __u32 padding; }; struct fuse_open_out { __u64 fh; __u32 open_flags; + __u32 padding; }; struct fuse_release_in { __u64 fh; __u32 flags; + __u32 padding; }; struct fuse_flush_in { __u64 fh; __u32 flush_flags; + __u32 padding; }; struct fuse_read_in { __u64 fh; __u64 offset; __u32 size; + __u32 padding; }; struct fuse_write_in { @@ -177,6 +187,7 @@ struct fuse_write_in { struct fuse_write_out { __u32 size; + __u32 padding; }; struct fuse_statfs_out { @@ -186,6 +197,7 @@ struct fuse_statfs_out { struct fuse_fsync_in { __u64 fh; __u32 fsync_flags; + __u32 padding; }; struct fuse_setxattr_in { @@ -195,10 +207,12 @@ struct fuse_setxattr_in { struct fuse_getxattr_in { __u32 size; + __u32 padding; }; struct fuse_getxattr_out { __u32 size; + __u32 padding; }; struct fuse_init_in_out { @@ -214,6 +228,7 @@ struct fuse_in_header { __u32 uid; __u32 gid; __u32 pid; + __u32 padding; }; struct fuse_out_header { -- GitLab From db50b96c0f28a21c5a4a19ecaba12d0972aab06a Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:33 -0700 Subject: [PATCH 272/563] [PATCH] FUSE - readpages operation This patch adds readpages support to FUSE. With the help of the readpages() operation multiple reads are bundled together and sent as a single request to userspace. This can improve reading performace. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/file.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 3 +++ fs/fuse/inode.c | 15 +++++++++++ 3 files changed, 85 insertions(+) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 96ea302db184b..86ffb6db5fe72 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -227,6 +227,72 @@ static int fuse_readpage(struct file *file, struct page *page) return err; } +static int fuse_send_readpages(struct fuse_req *req, struct file *file, + struct inode *inode) +{ + loff_t pos = (loff_t) req->pages[0]->index << PAGE_CACHE_SHIFT; + size_t count = req->num_pages << PAGE_CACHE_SHIFT; + unsigned i; + req->out.page_zeroing = 1; + fuse_send_read(req, file, inode, pos, count); + for (i = 0; i < req->num_pages; i++) { + struct page *page = req->pages[i]; + if (!req->out.h.error) + SetPageUptodate(page); + unlock_page(page); + } + return req->out.h.error; +} + +struct fuse_readpages_data { + struct fuse_req *req; + struct file *file; + struct inode *inode; +}; + +static int fuse_readpages_fill(void *_data, struct page *page) +{ + struct fuse_readpages_data *data = _data; + struct fuse_req *req = data->req; + struct inode *inode = data->inode; + struct fuse_conn *fc = get_fuse_conn(inode); + + if (req->num_pages && + (req->num_pages == FUSE_MAX_PAGES_PER_REQ || + (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read || + req->pages[req->num_pages - 1]->index + 1 != page->index)) { + int err = fuse_send_readpages(req, data->file, inode); + if (err) { + unlock_page(page); + return err; + } + fuse_reset_request(req); + } + req->pages[req->num_pages] = page; + req->num_pages ++; + return 0; +} + +static int fuse_readpages(struct file *file, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages) +{ + struct inode *inode = mapping->host; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_readpages_data data; + int err; + data.file = file; + data.inode = inode; + data.req = fuse_get_request_nonint(fc); + if (!data.req) + return -EINTR; + + err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); + if (!err && data.req->num_pages) + err = fuse_send_readpages(data.req, file, inode); + fuse_put_request(fc, data.req); + return err; +} + static ssize_t fuse_send_write(struct fuse_req *req, struct file *file, struct inode *inode, loff_t pos, size_t count) { @@ -331,6 +397,7 @@ static struct address_space_operations fuse_file_aops = { .readpage = fuse_readpage, .prepare_write = fuse_prepare_write, .commit_write = fuse_commit_write, + .readpages = fuse_readpages, .set_page_dirty = fuse_set_page_dirty, }; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 86183c5621048..aff3a01ea02b2 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -201,6 +201,9 @@ struct fuse_conn { /** The fuse mount flags for this mount */ unsigned flags; + /** Maximum read size */ + unsigned max_read; + /** Readers of the connection are waiting on this */ wait_queue_head_t waitq; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 458c62ca0fec1..0b75c73386e97 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -32,6 +32,7 @@ struct fuse_mount_data { unsigned rootmode; unsigned user_id; unsigned flags; + unsigned max_read; }; static struct inode *fuse_alloc_inode(struct super_block *sb) @@ -250,6 +251,7 @@ enum { OPT_DEFAULT_PERMISSIONS, OPT_ALLOW_OTHER, OPT_KERNEL_CACHE, + OPT_MAX_READ, OPT_ERR }; @@ -260,6 +262,7 @@ static match_table_t tokens = { {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, {OPT_ALLOW_OTHER, "allow_other"}, {OPT_KERNEL_CACHE, "kernel_cache"}, + {OPT_MAX_READ, "max_read=%u"}, {OPT_ERR, NULL} }; @@ -268,6 +271,7 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) char *p; memset(d, 0, sizeof(struct fuse_mount_data)); d->fd = -1; + d->max_read = ~0; while ((p = strsep(&opt, ",")) != NULL) { int token; @@ -308,6 +312,12 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) d->flags |= FUSE_KERNEL_CACHE; break; + case OPT_MAX_READ: + if (match_int(&args[0], &value)) + return 0; + d->max_read = value; + break; + default: return 0; } @@ -329,6 +339,8 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, ",allow_other"); if (fc->flags & FUSE_KERNEL_CACHE) seq_puts(m, ",kernel_cache"); + if (fc->max_read != ~0) + seq_printf(m, ",max_read=%u", fc->max_read); return 0; } @@ -453,6 +465,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) fc->flags = d.flags; fc->user_id = d.user_id; + fc->max_read = d.max_read; + if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) + fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; err = -ENOMEM; root = get_root_inode(sb, d.rootmode); -- GitLab From 87729a5514e855ce2c71e3e33833a106b8caf2ae Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:34 -0700 Subject: [PATCH 273/563] [PATCH] FUSE: tighten check for processes allowed access This patch tightens the check for allowing processes to access non-privileged mounts. The rational is that the filesystem implementation can control the behavior or get otherwise unavailable information of the filesystem user. If the filesystem user process has the same uid, gid, and is not suid or sgid application, then access is safe. Otherwise access is not allowed unless the "allow_other" mount option is given (for which policy is controlled by the userspace mount utility). Thanks to everyone linux-fsdevel, especially Martin Mares who helped uncover problems with the previous approach. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/dir.c | 40 ++++++++++++++++++++++++++++++++++------ fs/fuse/fuse_i.h | 3 +++ fs/fuse/inode.c | 12 ++++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index f127625543b4d..65da6e1b6de54 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -411,17 +411,45 @@ int fuse_do_getattr(struct inode *inode) return err; } +/* + * Calling into a user-controlled filesystem gives the filesystem + * daemon ptrace-like capabilities over the requester process. This + * means, that the filesystem daemon is able to record the exact + * filesystem operations performed, and can also control the behavior + * of the requester process in otherwise impossible ways. For example + * it can delay the operation for arbitrary length of time allowing + * DoS against the requester. + * + * For this reason only those processes can call into the filesystem, + * for which the owner of the mount has ptrace privilege. This + * excludes processes started by other users, suid or sgid processes. + */ +static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) +{ + if (fc->flags & FUSE_ALLOW_OTHER) + return 1; + + if (task->euid == fc->user_id && + task->suid == fc->user_id && + task->uid == fc->user_id && + task->egid == fc->group_id && + task->sgid == fc->group_id && + task->gid == fc->group_id) + return 1; + + return 0; +} + static int fuse_revalidate(struct dentry *entry) { struct inode *inode = entry->d_inode; struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_conn *fc = get_fuse_conn(inode); - if (get_node_id(inode) == FUSE_ROOT_ID) { - if (!(fc->flags & FUSE_ALLOW_OTHER) && - current->fsuid != fc->user_id) - return -EACCES; - } else if (time_before_eq(jiffies, fi->i_time)) + if (!fuse_allow_task(fc, current)) + return -EACCES; + if (get_node_id(inode) != FUSE_ROOT_ID && + time_before_eq(jiffies, fi->i_time)) return 0; return fuse_do_getattr(inode); @@ -431,7 +459,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) { struct fuse_conn *fc = get_fuse_conn(inode); - if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->user_id) + if (!fuse_allow_task(fc, current)) return -EACCES; else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { int err = generic_permission(inode, mask, NULL); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index aff3a01ea02b2..3ec2aff3fdb55 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -198,6 +198,9 @@ struct fuse_conn { /** The user id for this mount */ uid_t user_id; + /** The group id for this mount */ + gid_t group_id; + /** The fuse mount flags for this mount */ unsigned flags; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 0b75c73386e97..c8e54c0658f19 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -31,6 +31,7 @@ struct fuse_mount_data { int fd; unsigned rootmode; unsigned user_id; + unsigned group_id; unsigned flags; unsigned max_read; }; @@ -199,6 +200,7 @@ static void fuse_put_super(struct super_block *sb) spin_lock(&fuse_lock); fc->mounted = 0; fc->user_id = 0; + fc->group_id = 0; fc->flags = 0; /* Flush all readers on this fs */ wake_up_all(&fc->waitq); @@ -248,6 +250,7 @@ enum { OPT_FD, OPT_ROOTMODE, OPT_USER_ID, + OPT_GROUP_ID, OPT_DEFAULT_PERMISSIONS, OPT_ALLOW_OTHER, OPT_KERNEL_CACHE, @@ -259,6 +262,7 @@ static match_table_t tokens = { {OPT_FD, "fd=%u"}, {OPT_ROOTMODE, "rootmode=%o"}, {OPT_USER_ID, "user_id=%u"}, + {OPT_GROUP_ID, "group_id=%u"}, {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, {OPT_ALLOW_OTHER, "allow_other"}, {OPT_KERNEL_CACHE, "kernel_cache"}, @@ -300,6 +304,12 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) d->user_id = value; break; + case OPT_GROUP_ID: + if (match_int(&args[0], &value)) + return 0; + d->group_id = value; + break; + case OPT_DEFAULT_PERMISSIONS: d->flags |= FUSE_DEFAULT_PERMISSIONS; break; @@ -333,6 +343,7 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); seq_printf(m, ",user_id=%u", fc->user_id); + seq_printf(m, ",group_id=%u", fc->group_id); if (fc->flags & FUSE_DEFAULT_PERMISSIONS) seq_puts(m, ",default_permissions"); if (fc->flags & FUSE_ALLOW_OTHER) @@ -465,6 +476,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) fc->flags = d.flags; fc->user_id = d.user_id; + fc->group_id = d.group_id; fc->max_read = d.max_read; if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; -- GitLab From 5a53368277efa2d80dd2206dddc1f4b19ef0c32a Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:34 -0700 Subject: [PATCH 274/563] [PATCH] fuse: stricter mount option checking Check for the presence of all mandatory mount options. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/inode.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index c8e54c0658f19..298c1d4c15340 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -32,6 +32,10 @@ struct fuse_mount_data { unsigned rootmode; unsigned user_id; unsigned group_id; + unsigned fd_present : 1; + unsigned rootmode_present : 1; + unsigned user_id_present : 1; + unsigned group_id_present : 1; unsigned flags; unsigned max_read; }; @@ -274,7 +278,6 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) { char *p; memset(d, 0, sizeof(struct fuse_mount_data)); - d->fd = -1; d->max_read = ~0; while ((p = strsep(&opt, ",")) != NULL) { @@ -290,24 +293,28 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) if (match_int(&args[0], &value)) return 0; d->fd = value; + d->fd_present = 1; break; case OPT_ROOTMODE: if (match_octal(&args[0], &value)) return 0; d->rootmode = value; + d->rootmode_present = 1; break; case OPT_USER_ID: if (match_int(&args[0], &value)) return 0; d->user_id = value; + d->user_id_present = 1; break; case OPT_GROUP_ID: if (match_int(&args[0], &value)) return 0; d->group_id = value; + d->group_id_present = 1; break; case OPT_DEFAULT_PERMISSIONS: @@ -332,7 +339,9 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) return 0; } } - if (d->fd == -1) + + if (!d->fd_present || !d->rootmode_present || + !d->user_id_present || !d->group_id_present) return 0; return 1; -- GitLab From 413ef8cb302511d8e995e2b0e5517ee1a65b9c77 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:35 -0700 Subject: [PATCH 275/563] [PATCH] FUSE - direct I/O This patch adds support for the "direct_io" mount option of FUSE. When this mount option is specified, the page cache is bypassed for read and write operations. This is useful for example, if the filesystem doesn't know the size of files before reading them, or when any kind of caching is harmful. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/file.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++- fs/fuse/fuse_i.h | 6 +++ fs/fuse/inode.c | 9 ++++ 3 files changed, 146 insertions(+), 2 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 86ffb6db5fe72..6bc3fb26de399 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -363,6 +363,118 @@ static int fuse_commit_write(struct file *file, struct page *page, return err; } +static void fuse_release_user_pages(struct fuse_req *req, int write) +{ + unsigned i; + + for (i = 0; i < req->num_pages; i++) { + struct page *page = req->pages[i]; + if (write) + set_page_dirty_lock(page); + put_page(page); + } +} + +static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, + unsigned nbytes, int write) +{ + unsigned long user_addr = (unsigned long) buf; + unsigned offset = user_addr & ~PAGE_MASK; + int npages; + + /* This doesn't work with nfsd */ + if (!current->mm) + return -EPERM; + + nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); + npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; + npages = min(npages, FUSE_MAX_PAGES_PER_REQ); + down_read(¤t->mm->mmap_sem); + npages = get_user_pages(current, current->mm, user_addr, npages, write, + 0, req->pages, NULL); + up_read(¤t->mm->mmap_sem); + if (npages < 0) + return npages; + + req->num_pages = npages; + req->page_offset = offset; + return 0; +} + +static ssize_t fuse_direct_io(struct file *file, const char __user *buf, + size_t count, loff_t *ppos, int write) +{ + struct inode *inode = file->f_dentry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); + size_t nmax = write ? fc->max_write : fc->max_read; + loff_t pos = *ppos; + ssize_t res = 0; + struct fuse_req *req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + + while (count) { + size_t tmp; + size_t nres; + size_t nbytes = min(count, nmax); + int err = fuse_get_user_pages(req, buf, nbytes, !write); + if (err) { + res = err; + break; + } + tmp = (req->num_pages << PAGE_SHIFT) - req->page_offset; + nbytes = min(nbytes, tmp); + if (write) + nres = fuse_send_write(req, file, inode, pos, nbytes); + else + nres = fuse_send_read(req, file, inode, pos, nbytes); + fuse_release_user_pages(req, !write); + if (req->out.h.error) { + if (!res) + res = req->out.h.error; + break; + } else if (nres > nbytes) { + res = -EIO; + break; + } + count -= nres; + res += nres; + pos += nres; + buf += nres; + if (nres != nbytes) + break; + if (count) + fuse_reset_request(req); + } + fuse_put_request(fc, req); + if (res > 0) { + if (write && pos > i_size_read(inode)) + i_size_write(inode, pos); + *ppos = pos; + } else if (write && (res == -EINTR || res == -EIO)) + fuse_invalidate_attr(inode); + + return res; +} + +static ssize_t fuse_direct_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return fuse_direct_io(file, buf, count, ppos, 0); +} + +static ssize_t fuse_direct_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + ssize_t res; + /* Don't allow parallel writes to the same file */ + down(&inode->i_sem); + res = fuse_direct_io(file, buf, count, ppos, 1); + up(&inode->i_sem); + return res; +} + static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) { if ((vma->vm_flags & VM_SHARED)) { @@ -393,6 +505,17 @@ static struct file_operations fuse_file_operations = { .sendfile = generic_file_sendfile, }; +static struct file_operations fuse_direct_io_file_operations = { + .llseek = generic_file_llseek, + .read = fuse_direct_read, + .write = fuse_direct_write, + .open = fuse_open, + .flush = fuse_flush, + .release = fuse_release, + .fsync = fuse_fsync, + /* no mmap and sendfile */ +}; + static struct address_space_operations fuse_file_aops = { .readpage = fuse_readpage, .prepare_write = fuse_prepare_write, @@ -403,6 +526,12 @@ static struct address_space_operations fuse_file_aops = { void fuse_init_file_inode(struct inode *inode) { - inode->i_fop = &fuse_file_operations; - inode->i_data.a_ops = &fuse_file_aops; + struct fuse_conn *fc = get_fuse_conn(inode); + + if (fc->flags & FUSE_DIRECT_IO) + inode->i_fop = &fuse_direct_io_file_operations; + else { + inode->i_fop = &fuse_file_operations; + inode->i_data.a_ops = &fuse_file_aops; + } } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 3ec2aff3fdb55..0af1ac6469278 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -34,6 +34,9 @@ be flushed on open */ #define FUSE_KERNEL_CACHE (1 << 2) +/** Bypass the page cache for read and write operations */ +#define FUSE_DIRECT_IO (1 << 3) + /** FUSE inode */ struct fuse_inode { /** Inode data */ @@ -207,6 +210,9 @@ struct fuse_conn { /** Maximum read size */ unsigned max_read; + /** Maximum write size */ + unsigned max_write; + /** Readers of the connection are waiting on this */ wait_queue_head_t waitq; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 298c1d4c15340..652c9d5df9730 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -258,6 +258,7 @@ enum { OPT_DEFAULT_PERMISSIONS, OPT_ALLOW_OTHER, OPT_KERNEL_CACHE, + OPT_DIRECT_IO, OPT_MAX_READ, OPT_ERR }; @@ -270,6 +271,7 @@ static match_table_t tokens = { {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, {OPT_ALLOW_OTHER, "allow_other"}, {OPT_KERNEL_CACHE, "kernel_cache"}, + {OPT_DIRECT_IO, "direct_io"}, {OPT_MAX_READ, "max_read=%u"}, {OPT_ERR, NULL} }; @@ -329,6 +331,10 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) d->flags |= FUSE_KERNEL_CACHE; break; + case OPT_DIRECT_IO: + d->flags |= FUSE_DIRECT_IO; + break; + case OPT_MAX_READ: if (match_int(&args[0], &value)) return 0; @@ -359,6 +365,8 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, ",allow_other"); if (fc->flags & FUSE_KERNEL_CACHE) seq_puts(m, ",kernel_cache"); + if (fc->flags & FUSE_DIRECT_IO) + seq_puts(m, ",direct_io"); if (fc->max_read != ~0) seq_printf(m, ",max_read=%u", fc->max_read); return 0; @@ -489,6 +497,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) fc->max_read = d.max_read; if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; + fc->max_write = FUSE_MAX_IN / 2; err = -ENOMEM; root = get_root_inode(sb, d.rootmode); -- GitLab From 04730fef1f9c7277e5c730b193e681ac095b0507 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:36 -0700 Subject: [PATCH 276/563] [PATCH] fuse: transfer readdir data through device This patch removes a long lasting "hack" in FUSE, which used a separate channel (a file descriptor refering to a disk-file) to transfer directory contents from userspace to the kernel. The patch adds three new operations (OPENDIR, READDIR, RELEASEDIR), which have semantics and implementation exactly maching the respective file operations (OPEN, READ, RELEASE). This simplifies the directory reading code. Also disk space is not necessary, which can be important in embedded systems. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/dev.c | 9 ----- fs/fuse/dir.c | 84 +++++++++++++------------------------------- fs/fuse/file.c | 38 ++++++++++++++------ fs/fuse/fuse_i.h | 22 +++++++++--- include/linux/fuse.h | 10 +++--- 5 files changed, 73 insertions(+), 90 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index ca6fc0e96d7c7..e4ada021d0876 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -731,13 +731,6 @@ static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique) return NULL; } -/* fget() needs to be done in this context */ -static void process_getdir(struct fuse_req *req) -{ - struct fuse_getdir_out_i *arg = req->out.args[0].value; - arg->file = fget(arg->fd); -} - static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out, unsigned nbytes) { @@ -817,8 +810,6 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov, if (!err) { if (req->interrupted) err = -ENOENT; - else if (req->in.h.opcode == FUSE_GETDIR && !oh.error) - process_getdir(req); } else if (!req->interrupted) req->out.h.error = -EIO; request_end(fc, req); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 65da6e1b6de54..cf5d1faed7af4 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -519,70 +519,40 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file, return 0; } -static int fuse_checkdir(struct file *cfile, struct file *file) +static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, + size_t count) { - struct inode *inode; - if (!cfile) - return -EIO; - inode = cfile->f_dentry->d_inode; - if (!S_ISREG(inode->i_mode)) { - fput(cfile); - return -EIO; - } - - file->private_data = cfile; - return 0; + return fuse_send_read_common(req, file, inode, pos, count, 1); } -static int fuse_getdir(struct file *file) +static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) { + int err; + size_t nbytes; + struct page *page; struct inode *inode = file->f_dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req = fuse_get_request(fc); - struct fuse_getdir_out_i outarg; - int err; - + struct fuse_req *req = fuse_get_request_nonint(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; - req->in.h.opcode = FUSE_GETDIR; - req->in.h.nodeid = get_node_id(inode); - req->inode = inode; - req->out.numargs = 1; - req->out.args[0].size = sizeof(struct fuse_getdir_out); - req->out.args[0].value = &outarg; - request_send(fc, req); + page = alloc_page(GFP_KERNEL); + if (!page) { + fuse_put_request(fc, req); + return -ENOMEM; + } + req->num_pages = 1; + req->pages[0] = page; + nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE); err = req->out.h.error; fuse_put_request(fc, req); if (!err) - err = fuse_checkdir(outarg.file, file); - return err; -} - -static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) -{ - struct file *cfile = file->private_data; - char *buf; - int ret; - - if (!cfile) { - ret = fuse_getdir(file); - if (ret) - return ret; - - cfile = file->private_data; - } + err = parse_dirfile(page_address(page), nbytes, file, dstbuf, + filldir); - buf = (char *) __get_free_page(GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE); - if (ret > 0) - ret = parse_dirfile(buf, ret, file, dstbuf, filldir); - - free_page((unsigned long) buf); - return ret; + __free_page(page); + return err; } static char *read_link(struct dentry *dentry) @@ -637,18 +607,12 @@ static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) static int fuse_dir_open(struct inode *inode, struct file *file) { - file->private_data = NULL; - return 0; + return fuse_open_common(inode, file, 1); } static int fuse_dir_release(struct inode *inode, struct file *file) { - struct file *cfile = file->private_data; - - if (cfile) - fput(cfile); - - return 0; + return fuse_release_common(inode, file, 1); } static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 6bc3fb26de399..224453557cf65 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -12,7 +12,7 @@ #include <linux/slab.h> #include <linux/kernel.h> -static int fuse_open(struct inode *inode, struct file *file) +int fuse_open_common(struct inode *inode, struct file *file, int isdir) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req; @@ -56,7 +56,7 @@ static int fuse_open(struct inode *inode, struct file *file) memset(&inarg, 0, sizeof(inarg)); inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - req->in.h.opcode = FUSE_OPEN; + req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; req->in.h.nodeid = get_node_id(inode); req->inode = inode; req->in.numargs = 1; @@ -85,7 +85,7 @@ static int fuse_open(struct inode *inode, struct file *file) return err; } -static int fuse_release(struct inode *inode, struct file *file) +int fuse_release_common(struct inode *inode, struct file *file, int isdir) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; @@ -94,7 +94,7 @@ static int fuse_release(struct inode *inode, struct file *file) inarg->fh = ff->fh; inarg->flags = file->f_flags & ~O_EXCL; - req->in.h.opcode = FUSE_RELEASE; + req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; req->in.h.nodeid = get_node_id(inode); req->inode = inode; req->in.numargs = 1; @@ -107,6 +107,16 @@ static int fuse_release(struct inode *inode, struct file *file) return 0; } +static int fuse_open(struct inode *inode, struct file *file) +{ + return fuse_open_common(inode, file, 0); +} + +static int fuse_release(struct inode *inode, struct file *file) +{ + return fuse_release_common(inode, file, 0); +} + static int fuse_flush(struct file *file) { struct inode *inode = file->f_dentry->d_inode; @@ -178,8 +188,9 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync) return err; } -static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, - struct inode *inode, loff_t pos, size_t count) +size_t fuse_send_read_common(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count, + int isdir) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; @@ -189,7 +200,7 @@ static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, inarg.fh = ff->fh; inarg.offset = pos; inarg.size = count; - req->in.h.opcode = FUSE_READ; + req->in.h.opcode = isdir ? FUSE_READDIR : FUSE_READ; req->in.h.nodeid = get_node_id(inode); req->inode = inode; req->file = file; @@ -204,6 +215,13 @@ static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, return req->out.args[0].size; } +static inline size_t fuse_send_read(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, + size_t count) +{ + return fuse_send_read_common(req, file, inode, pos, count, 0); +} + static int fuse_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; @@ -293,8 +311,8 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, return err; } -static ssize_t fuse_send_write(struct fuse_req *req, struct file *file, - struct inode *inode, loff_t pos, size_t count) +static size_t fuse_send_write(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; @@ -332,7 +350,7 @@ static int fuse_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) { int err; - ssize_t nres; + size_t nres; unsigned count = to - offset; struct inode *inode = page->mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 0af1ac6469278..8593d5bae7a60 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -273,11 +273,6 @@ struct fuse_conn { struct backing_dev_info bdi; }; -struct fuse_getdir_out_i { - int fd; - void *file; /* Used by kernel only */ -}; - static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb) { return (struct fuse_conn **) &sb->s_fs_info; @@ -333,6 +328,23 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, unsigned long nodeid, u64 nlookup); +/** + * Send READ or READDIR request + */ +size_t fuse_send_read_common(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count, + int isdir); + +/** + * Send OPEN or OPENDIR request + */ +int fuse_open_common(struct inode *inode, struct file *file, int isdir); + +/** + * Send RELEASE or RELEASEDIR request + */ +int fuse_release_common(struct inode *inode, struct file *file, int isdir); + /** * Initialise file operations on a regular file */ diff --git a/include/linux/fuse.h b/include/linux/fuse.h index e9b814e16c586..cdfaa51b90186 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -70,7 +70,6 @@ enum fuse_opcode { FUSE_SETATTR = 4, FUSE_READLINK = 5, FUSE_SYMLINK = 6, - FUSE_GETDIR = 7, FUSE_MKNOD = 8, FUSE_MKDIR = 9, FUSE_UNLINK = 10, @@ -88,7 +87,10 @@ enum fuse_opcode { FUSE_LISTXATTR = 23, FUSE_REMOVEXATTR = 24, FUSE_FLUSH = 25, - FUSE_INIT = 26 + FUSE_INIT = 26, + FUSE_OPENDIR = 27, + FUSE_READDIR = 28, + FUSE_RELEASEDIR = 29 }; /* Conservative buffer size for the client */ @@ -120,10 +122,6 @@ struct fuse_attr_out { struct fuse_attr attr; }; -struct fuse_getdir_out { - __u32 fd; -}; - struct fuse_mknod_in { __u32 mode; __u32 rdev; -- GitLab From 45323fb76465a9576220c7427dbac7b1e7ad3caf Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:37 -0700 Subject: [PATCH 277/563] [PATCH] fuse: more flexible caching Make data caching behavior selectable on a per-open basis instead of per-mount. Compatibility for the old mount options 'kernel_cache' and 'direct_io' is retained in the userspace library (version 2.4.0-pre1 or later). Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/filesystems/fuse.txt | 26 -------------------------- fs/fuse/file.c | 18 ++++++++---------- fs/fuse/fuse_i.h | 6 ------ fs/fuse/inode.c | 16 ---------------- include/linux/fuse.h | 11 ++++++++++- 5 files changed, 18 insertions(+), 59 deletions(-) diff --git a/Documentation/filesystems/fuse.txt b/Documentation/filesystems/fuse.txt index 83f96cf569603..6b5741e651a2a 100644 --- a/Documentation/filesystems/fuse.txt +++ b/Documentation/filesystems/fuse.txt @@ -80,32 +80,6 @@ Mount options allowed to root, but this restriction can be removed with a (userspace) configuration option. -'kernel_cache' - - This option disables flushing the cache of the file contents on - every open(). This should only be enabled on filesystems, where the - file data is never changed externally (not through the mounted FUSE - filesystem). Thus it is not suitable for network filesystems and - other "intermediate" filesystems. - - NOTE: if this option is not specified (and neither 'direct_io') data - is still cached after the open(), so a read() system call will not - always initiate a read operation. - -'direct_io' - - This option disables the use of page cache (file content cache) in - the kernel for this filesystem. This has several affects: - - - Each read() or write() system call will initiate one or more - read or write operations, data will not be cached in the - kernel. - - - The return value of the read() and write() system calls will - correspond to the return values of the read and write - operations. This is useful for example if the file size is not - known in advance (before reading it). - 'max_read=N' With this option the maximum size of read operations can be set. diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 224453557cf65..a8dc88527fbe6 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -12,6 +12,8 @@ #include <linux/slab.h> #include <linux/kernel.h> +static struct file_operations fuse_direct_io_file_operations; + int fuse_open_common(struct inode *inode, struct file *file, int isdir) { struct fuse_conn *fc = get_fuse_conn(inode); @@ -70,12 +72,14 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) else request_send(fc, req); err = req->out.h.error; - if (!err && !(fc->flags & FUSE_KERNEL_CACHE)) - invalidate_inode_pages(inode->i_mapping); if (err) { fuse_request_free(ff->release_req); kfree(ff); } else { + if (!isdir && (outarg.open_flags & FOPEN_DIRECT_IO)) + file->f_op = &fuse_direct_io_file_operations; + if (!(outarg.open_flags & FOPEN_KEEP_CACHE)) + invalidate_inode_pages(inode->i_mapping); ff->fh = outarg.fh; file->private_data = ff; } @@ -544,12 +548,6 @@ static struct address_space_operations fuse_file_aops = { void fuse_init_file_inode(struct inode *inode) { - struct fuse_conn *fc = get_fuse_conn(inode); - - if (fc->flags & FUSE_DIRECT_IO) - inode->i_fop = &fuse_direct_io_file_operations; - else { - inode->i_fop = &fuse_file_operations; - inode->i_data.a_ops = &fuse_file_aops; - } + inode->i_fop = &fuse_file_operations; + inode->i_data.a_ops = &fuse_file_aops; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 8593d5bae7a60..84849601363ea 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -30,12 +30,6 @@ doing the mount will be allowed to access the filesystem */ #define FUSE_ALLOW_OTHER (1 << 1) -/** If the FUSE_KERNEL_CACHE flag is given, then cached data will not - be flushed on open */ -#define FUSE_KERNEL_CACHE (1 << 2) - -/** Bypass the page cache for read and write operations */ -#define FUSE_DIRECT_IO (1 << 3) /** FUSE inode */ struct fuse_inode { diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 652c9d5df9730..8dc66760b41a9 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -257,8 +257,6 @@ enum { OPT_GROUP_ID, OPT_DEFAULT_PERMISSIONS, OPT_ALLOW_OTHER, - OPT_KERNEL_CACHE, - OPT_DIRECT_IO, OPT_MAX_READ, OPT_ERR }; @@ -270,8 +268,6 @@ static match_table_t tokens = { {OPT_GROUP_ID, "group_id=%u"}, {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, {OPT_ALLOW_OTHER, "allow_other"}, - {OPT_KERNEL_CACHE, "kernel_cache"}, - {OPT_DIRECT_IO, "direct_io"}, {OPT_MAX_READ, "max_read=%u"}, {OPT_ERR, NULL} }; @@ -327,14 +323,6 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) d->flags |= FUSE_ALLOW_OTHER; break; - case OPT_KERNEL_CACHE: - d->flags |= FUSE_KERNEL_CACHE; - break; - - case OPT_DIRECT_IO: - d->flags |= FUSE_DIRECT_IO; - break; - case OPT_MAX_READ: if (match_int(&args[0], &value)) return 0; @@ -363,10 +351,6 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, ",default_permissions"); if (fc->flags & FUSE_ALLOW_OTHER) seq_puts(m, ",allow_other"); - if (fc->flags & FUSE_KERNEL_CACHE) - seq_puts(m, ",kernel_cache"); - if (fc->flags & FUSE_DIRECT_IO) - seq_puts(m, ",direct_io"); if (fc->max_read != ~0) seq_printf(m, ",max_read=%u", fc->max_read); return 0; diff --git a/include/linux/fuse.h b/include/linux/fuse.h index cdfaa51b90186..c65124a213a12 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -14,7 +14,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 1 +#define FUSE_KERNEL_MINOR_VERSION 2 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -63,6 +63,15 @@ struct fuse_kstatfs { #define FATTR_MTIME (1 << 5) #define FATTR_CTIME (1 << 6) +/** + * Flags returned by the OPEN request + * + * FOPEN_DIRECT_IO: bypass page cache for this open file + * FOPEN_KEEP_CACHE: don't invalidate the data cache on open + */ +#define FOPEN_DIRECT_IO (1 << 0) +#define FOPEN_KEEP_CACHE (1 << 1) + enum fuse_opcode { FUSE_LOOKUP = 1, FUSE_FORGET = 2, /* no reply */ -- GitLab From b36c31ba95f0fe0a03c727300d9c4c54438a5636 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:38 -0700 Subject: [PATCH 278/563] [PATCH] fuse: don't update file times Don't change mtime/ctime/atime to local time on read/write. Rather invalidate file attributes, so next stat() will force a GETATTR call. Bug reported by Ben Grimm. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/dir.c | 2 ++ fs/fuse/file.c | 10 ++++++---- fs/fuse/inode.c | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index cf5d1faed7af4..9b43fd46aaad5 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -552,6 +552,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) filldir); __free_page(page); + fuse_invalidate_attr(inode); /* atime changed */ return err; } @@ -585,6 +586,7 @@ static char *read_link(struct dentry *dentry) link[req->out.args[0].size] = '\0'; out: fuse_put_request(fc, req); + fuse_invalidate_attr(inode); /* atime changed */ return link; } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a8dc88527fbe6..6dcae74ce7fa0 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -244,6 +244,7 @@ static int fuse_readpage(struct file *file, struct page *page) fuse_put_request(fc, req); if (!err) SetPageUptodate(page); + fuse_invalidate_attr(inode); /* atime changed */ out: unlock_page(page); return err; @@ -312,6 +313,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, if (!err && data.req->num_pages) err = fuse_send_readpages(data.req, file, inode); fuse_put_request(fc, data.req); + fuse_invalidate_attr(inode); /* atime changed */ return err; } @@ -380,8 +382,8 @@ static int fuse_commit_write(struct file *file, struct page *page, clear_page_dirty(page); SetPageUptodate(page); } - } else if (err == -EINTR || err == -EIO) - fuse_invalidate_attr(inode); + } + fuse_invalidate_attr(inode); return err; } @@ -473,8 +475,8 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, if (write && pos > i_size_read(inode)) i_size_write(inode, pos); *ppos = pos; - } else if (write && (res == -EINTR || res == -EIO)) - fuse_invalidate_attr(inode); + } + fuse_invalidate_attr(inode); return res; } diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 8dc66760b41a9..52e954f4bb912 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -173,6 +173,7 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, return NULL; if ((inode->i_state & I_NEW)) { + inode->i_flags |= S_NOATIME|S_NOCMTIME; inode->i_generation = generation; inode->i_data.backing_dev_info = &fc->bdi; fuse_init_inode(inode, attr); -- GitLab From 8254798199332966e2ab647380c990193af7e854 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:38 -0700 Subject: [PATCH 279/563] [PATCH] FUSE: add fsync operation for directories This patch adds a new FSYNCDIR request, which is sent when fsync is called on directories. This operation is available in libfuse 2.3-pre1 or greater. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/dir.c | 7 +++++++ fs/fuse/file.c | 17 +++++++++++++---- fs/fuse/fuse_i.h | 9 +++++++++ include/linux/fuse.h | 3 ++- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 9b43fd46aaad5..73792d65b6cff 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -617,6 +617,12 @@ static int fuse_dir_release(struct inode *inode, struct file *file) return fuse_release_common(inode, file, 1); } +static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) +{ + /* nfsd can call this with no file */ + return file ? fuse_fsync_common(file, de, datasync, 1) : 0; +} + static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) { unsigned ivalid = iattr->ia_valid; @@ -934,6 +940,7 @@ static struct file_operations fuse_dir_operations = { .readdir = fuse_readdir, .open = fuse_dir_open, .release = fuse_dir_release, + .fsync = fuse_dir_fsync, }; static struct inode_operations fuse_common_inode_operations = { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 6dcae74ce7fa0..e225f8c0b2679 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -156,7 +156,8 @@ static int fuse_flush(struct file *file) return err; } -static int fuse_fsync(struct file *file, struct dentry *de, int datasync) +int fuse_fsync_common(struct file *file, struct dentry *de, int datasync, + int isdir) { struct inode *inode = de->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); @@ -165,7 +166,7 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync) struct fuse_fsync_in inarg; int err; - if (fc->no_fsync) + if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) return 0; req = fuse_get_request(fc); @@ -175,7 +176,7 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync) memset(&inarg, 0, sizeof(inarg)); inarg.fh = ff->fh; inarg.fsync_flags = datasync ? 1 : 0; - req->in.h.opcode = FUSE_FSYNC; + req->in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC; req->in.h.nodeid = get_node_id(inode); req->inode = inode; req->file = file; @@ -186,12 +187,20 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync) err = req->out.h.error; fuse_put_request(fc, req); if (err == -ENOSYS) { - fc->no_fsync = 1; + if (isdir) + fc->no_fsyncdir = 1; + else + fc->no_fsync = 1; err = 0; } return err; } +static int fuse_fsync(struct file *file, struct dentry *de, int datasync) +{ + return fuse_fsync_common(file, de, datasync, 0); +} + size_t fuse_send_read_common(struct fuse_req *req, struct file *file, struct inode *inode, loff_t pos, size_t count, int isdir) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 84849601363ea..d7647289d8a1b 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -248,6 +248,9 @@ struct fuse_conn { /** Is fsync not implemented by fs? */ unsigned no_fsync : 1; + /** Is fsyncdir not implemented by fs? */ + unsigned no_fsyncdir : 1; + /** Is flush not implemented by fs? */ unsigned no_flush : 1; @@ -339,6 +342,12 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir); */ int fuse_release_common(struct inode *inode, struct file *file, int isdir); +/** + * Send FSYNC or FSYNCDIR request + */ +int fuse_fsync_common(struct file *file, struct dentry *de, int datasync, + int isdir); + /** * Initialise file operations on a regular file */ diff --git a/include/linux/fuse.h b/include/linux/fuse.h index c65124a213a12..acbeb96a33530 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -99,7 +99,8 @@ enum fuse_opcode { FUSE_INIT = 26, FUSE_OPENDIR = 27, FUSE_READDIR = 28, - FUSE_RELEASEDIR = 29 + FUSE_RELEASEDIR = 29, + FUSE_FSYNCDIR = 30 }; /* Conservative buffer size for the client */ -- GitLab From 7c352bdf048811b8128019ffc1e886161e09c11c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi <miklos@szeredi.hu> Date: Fri, 9 Sep 2005 13:10:39 -0700 Subject: [PATCH 280/563] [PATCH] FUSE: don't allow restarting of system calls This patch removes ability to interrupt and restart operations while there hasn't been any side-effect. The reason: applications. There are some apps it seems that generate signals at a fast rate. This means, that if the operation cannot make enough progress between two signals, it will be restarted for ever. This bug actually manifested itself with 'krusader' trying to open a file for writing under sshfs. Thanks to Eduard Czimbalmos for the report. The problem can be solved just by making open() uninterruptible, because in this case it was the truncate operation that slowed down the progress. But it's better to solve this by simply not allowing interrupts at all (except SIGKILL), because applications don't expect file operations to be interruptible anyway. As an added bonus the code is simplified somewhat. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/fuse/dev.c | 73 +++++++++--------------------------------------- fs/fuse/dir.c | 36 ++++++++++++------------ fs/fuse/file.c | 33 ++++++++-------------- fs/fuse/fuse_i.h | 12 +------- fs/fuse/inode.c | 2 +- 5 files changed, 45 insertions(+), 111 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index e4ada021d0876..d4c869c6d01b2 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -103,19 +103,8 @@ static struct fuse_req *do_get_request(struct fuse_conn *fc) return req; } +/* This can return NULL, but only in case it's interrupted by a SIGKILL */ struct fuse_req *fuse_get_request(struct fuse_conn *fc) -{ - if (down_interruptible(&fc->outstanding_sem)) - return NULL; - return do_get_request(fc); -} - -/* - * Non-interruptible version of the above function is for operations - * which can't legally return -ERESTART{SYS,NOINTR}. This can still - * return NULL, but only in case the signal is SIGKILL. - */ -struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc) { int intr; sigset_t oldset; @@ -241,43 +230,20 @@ static void background_request(struct fuse_conn *fc, struct fuse_req *req) get_file(req->file); } -static int request_wait_answer_nonint(struct fuse_req *req) -{ - int err; - sigset_t oldset; - block_sigs(&oldset); - err = wait_event_interruptible(req->waitq, req->finished); - restore_sigs(&oldset); - return err; -} - /* Called with fuse_lock held. Releases, and then reacquires it. */ -static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req, - int interruptible) +static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) { - int intr; + sigset_t oldset; spin_unlock(&fuse_lock); - if (interruptible) - intr = wait_event_interruptible(req->waitq, req->finished); - else - intr = request_wait_answer_nonint(req); + block_sigs(&oldset); + wait_event_interruptible(req->waitq, req->finished); + restore_sigs(&oldset); spin_lock(&fuse_lock); - if (intr && interruptible && req->sent) { - /* If request is already in userspace, only allow KILL - signal to interrupt */ - spin_unlock(&fuse_lock); - intr = request_wait_answer_nonint(req); - spin_lock(&fuse_lock); - } - if (!intr) + if (req->finished) return; - if (!interruptible || req->sent) - req->out.h.error = -EINTR; - else - req->out.h.error = -ERESTARTNOINTR; - + req->out.h.error = -EINTR; req->interrupted = 1; if (req->locked) { /* This is uninterruptible sleep, because data is @@ -330,8 +296,10 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req) wake_up(&fc->waitq); } -static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req, - int interruptible) +/* + * This can only be interrupted by a SIGKILL + */ +void request_send(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 1; spin_lock(&fuse_lock); @@ -345,26 +313,11 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req, after request_end() */ __fuse_get_request(req); - request_wait_answer(fc, req, interruptible); + request_wait_answer(fc, req); } spin_unlock(&fuse_lock); } -void request_send(struct fuse_conn *fc, struct fuse_req *req) -{ - request_send_wait(fc, req, 1); -} - -/* - * Non-interruptible version of the above function is for operations - * which can't legally return -ERESTART{SYS,NOINTR}. This can still - * be interrupted but only with SIGKILL. - */ -void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req) -{ - request_send_wait(fc, req, 0); -} - static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) { spin_lock(&fuse_lock); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 73792d65b6cff..e79e49b3eec7e 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -46,12 +46,12 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) struct inode *inode = entry->d_inode; struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req = fuse_get_request_nonint(fc); + struct fuse_req *req = fuse_get_request(fc); if (!req) return 0; fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); - request_send_nonint(fc, req); + request_send(fc, req); err = req->out.h.error; if (!err) { if (outarg.nodeid != get_node_id(inode)) { @@ -91,7 +91,7 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry, req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; fuse_lookup_init(req, dir, entry, &outarg); request_send(fc, req); @@ -185,7 +185,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_req *req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; memset(&inarg, 0, sizeof(inarg)); inarg.mode = mode; @@ -211,7 +211,7 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_req *req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; memset(&inarg, 0, sizeof(inarg)); inarg.mode = mode; @@ -236,7 +236,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry, req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; req->in.h.opcode = FUSE_SYMLINK; req->in.numargs = 2; @@ -253,7 +253,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_req *req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; req->in.h.opcode = FUSE_UNLINK; req->in.h.nodeid = get_node_id(dir); @@ -284,7 +284,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_req *req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; req->in.h.opcode = FUSE_RMDIR; req->in.h.nodeid = get_node_id(dir); @@ -311,7 +311,7 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent, struct fuse_conn *fc = get_fuse_conn(olddir); struct fuse_req *req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; memset(&inarg, 0, sizeof(inarg)); inarg.newdir = get_node_id(newdir); @@ -356,7 +356,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; memset(&inarg, 0, sizeof(inarg)); inarg.oldnodeid = get_node_id(inode); @@ -386,7 +386,7 @@ int fuse_do_getattr(struct inode *inode) struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; req->in.h.opcode = FUSE_GETATTR; req->in.h.nodeid = get_node_id(inode); @@ -533,7 +533,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) struct page *page; struct inode *inode = file->f_dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req = fuse_get_request_nonint(fc); + struct fuse_req *req = fuse_get_request(fc); if (!req) return -EINTR; @@ -564,7 +564,7 @@ static char *read_link(struct dentry *dentry) char *link; if (!req) - return ERR_PTR(-ERESTARTNOINTR); + return ERR_PTR(-EINTR); link = (char *) __get_free_page(GFP_KERNEL); if (!link) { @@ -677,7 +677,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; memset(&inarg, 0, sizeof(inarg)); inarg.valid = iattr_to_fattr(attr, &inarg.attr); @@ -761,7 +761,7 @@ static int fuse_setxattr(struct dentry *entry, const char *name, req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; memset(&inarg, 0, sizeof(inarg)); inarg.size = size; @@ -801,7 +801,7 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name, req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; memset(&inarg, 0, sizeof(inarg)); inarg.size = size; @@ -851,7 +851,7 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; memset(&inarg, 0, sizeof(inarg)); inarg.size = size; @@ -897,7 +897,7 @@ static int fuse_removexattr(struct dentry *entry, const char *name) req = fuse_get_request(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; req->in.h.opcode = FUSE_REMOVEXATTR; req->in.h.nodeid = get_node_id(inode); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index e225f8c0b2679..6454022b05367 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -22,9 +22,6 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) struct fuse_open_out outarg; struct fuse_file *ff; int err; - /* Restarting the syscall is not allowed if O_CREAT and O_EXCL - are both set, because creation will fail on the restart */ - int excl = (file->f_flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL); err = generic_file_open(inode, file); if (err) @@ -38,12 +35,9 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) return err; } - if (excl) - req = fuse_get_request_nonint(fc); - else - req = fuse_get_request(fc); + req = fuse_get_request(fc); if (!req) - return excl ? -EINTR : -ERESTARTSYS; + return -EINTR; err = -ENOMEM; ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL); @@ -67,10 +61,7 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) req->out.numargs = 1; req->out.args[0].size = sizeof(outarg); req->out.args[0].value = &outarg; - if (excl) - request_send_nonint(fc, req); - else - request_send(fc, req); + request_send(fc, req); err = req->out.h.error; if (err) { fuse_request_free(ff->release_req); @@ -133,7 +124,7 @@ static int fuse_flush(struct file *file) if (fc->no_flush) return 0; - req = fuse_get_request_nonint(fc); + req = fuse_get_request(fc); if (!req) return -EINTR; @@ -146,7 +137,7 @@ static int fuse_flush(struct file *file) req->in.numargs = 1; req->in.args[0].size = sizeof(inarg); req->in.args[0].value = &inarg; - request_send_nonint(fc, req); + request_send(fc, req); err = req->out.h.error; fuse_put_request(fc, req); if (err == -ENOSYS) { @@ -171,7 +162,7 @@ int fuse_fsync_common(struct file *file, struct dentry *de, int datasync, req = fuse_get_request(fc); if (!req) - return -ERESTARTSYS; + return -EINTR; memset(&inarg, 0, sizeof(inarg)); inarg.fh = ff->fh; @@ -224,7 +215,7 @@ size_t fuse_send_read_common(struct fuse_req *req, struct file *file, req->out.argvar = 1; req->out.numargs = 1; req->out.args[0].size = count; - request_send_nonint(fc, req); + request_send(fc, req); return req->out.args[0].size; } @@ -240,7 +231,7 @@ static int fuse_readpage(struct file *file, struct page *page) struct inode *inode = page->mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); loff_t pos = (loff_t) page->index << PAGE_CACHE_SHIFT; - struct fuse_req *req = fuse_get_request_nonint(fc); + struct fuse_req *req = fuse_get_request(fc); int err = -EINTR; if (!req) goto out; @@ -314,7 +305,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, int err; data.file = file; data.inode = inode; - data.req = fuse_get_request_nonint(fc); + data.req = fuse_get_request(fc); if (!data.req) return -EINTR; @@ -350,7 +341,7 @@ static size_t fuse_send_write(struct fuse_req *req, struct file *file, req->out.numargs = 1; req->out.args[0].size = sizeof(struct fuse_write_out); req->out.args[0].value = &outarg; - request_send_nonint(fc, req); + request_send(fc, req); return outarg.size; } @@ -370,7 +361,7 @@ static int fuse_commit_write(struct file *file, struct page *page, struct inode *inode = page->mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset; - struct fuse_req *req = fuse_get_request_nonint(fc); + struct fuse_req *req = fuse_get_request(fc); if (!req) return -EINTR; @@ -444,7 +435,7 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, ssize_t res = 0; struct fuse_req *req = fuse_get_request(fc); if (!req) - return -ERESTARTSYS; + return -EINTR; while (count) { size_t tmp; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index d7647289d8a1b..24d761518d864 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -409,11 +409,6 @@ void fuse_reset_request(struct fuse_req *req); */ struct fuse_req *fuse_get_request(struct fuse_conn *fc); -/** - * Reserve a preallocated request, only interruptible by SIGKILL - */ -struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc); - /** * Decrement reference count of a request. If count goes to zero put * on unused list (preallocated) or free reqest (not preallocated). @@ -421,15 +416,10 @@ struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc); void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); /** - * Send a request (synchronous, interruptible) + * Send a request (synchronous) */ void request_send(struct fuse_conn *fc, struct fuse_req *req); -/** - * Send a request (synchronous, non-interruptible except by SIGKILL) - */ -void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req); - /** * Send a request with no reply */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 52e954f4bb912..e69a546844d0f 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -236,7 +236,7 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf) req = fuse_get_request(fc); if (!req) - return -ERESTARTSYS; + return -EINTR; req->in.numargs = 0; req->in.h.opcode = FUSE_STATFS; -- GitLab From 8d06afab73a75f40ae2864e6c296356bab1ab473 Mon Sep 17 00:00:00 2001 From: Ingo Molnar <mingo@elte.hu> Date: Fri, 9 Sep 2005 13:10:40 -0700 Subject: [PATCH 281/563] [PATCH] timer initialization cleanup: DEFINE_TIMER Clean up timer initialization by introducing DEFINE_TIMER a'la DEFINE_SPINLOCK. Build and boot-tested on x86. A similar patch has been been in the -RT tree for some time. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/kernel/time.c | 3 +-- arch/m68k/amiga/amisound.c | 2 +- arch/m68k/mac/macboing.c | 3 +-- arch/ppc/8xx_io/cs4218_tdm.c | 2 +- drivers/acorn/block/fd1772.c | 12 ++++-------- drivers/atm/idt77105.c | 6 ++---- drivers/atm/iphase.c | 2 +- drivers/block/acsi.c | 2 +- drivers/block/acsi_slm.c | 2 +- drivers/block/ataflop.c | 14 ++++---------- drivers/block/floppy.c | 4 ++-- drivers/block/ps2esdi.c | 3 +-- drivers/cdrom/aztcd.c | 2 +- drivers/cdrom/gscd.c | 2 +- drivers/cdrom/optcd.c | 2 +- drivers/cdrom/sbpcd.c | 9 +++------ drivers/cdrom/sjcd.c | 2 +- drivers/char/cyclades.c | 2 +- drivers/char/hangcheck-timer.c | 3 +-- drivers/char/ip2main.c | 2 +- drivers/char/istallion.c | 2 +- drivers/char/keyboard.c | 3 +-- drivers/char/watchdog/mixcomwd.c | 2 +- drivers/net/atari_bionet.c | 2 +- drivers/net/atari_pamsnet.c | 2 +- drivers/net/cris/eth_v10.c | 6 +++--- drivers/net/hamradio/yam.c | 2 +- drivers/sbus/char/aurora.c | 3 +-- drivers/scsi/pluto.c | 3 +-- drivers/usb/host/hc_crisv10.c | 4 ++-- include/linux/timer.h | 4 ++++ mm/page-writeback.c | 6 ++---- net/atm/mpc.c | 2 +- net/core/dst.c | 3 +-- net/decnet/dn_route.c | 3 +-- net/ipv4/inetpeer.c | 3 +-- net/ipv6/addrconf.c | 3 +-- net/ipv6/ip6_fib.c | 2 +- net/ipv6/ip6_flowlabel.c | 2 +- net/netrom/nr_loopback.c | 2 +- net/sched/sch_api.c | 2 +- sound/oss/midibuf.c | 2 +- sound/oss/soundcard.c | 3 +-- sound/oss/sys_timer.c | 3 +-- sound/oss/uart6850.c | 3 +-- 45 files changed, 62 insertions(+), 89 deletions(-) diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index eefea7c550089..2883a4d4f01f8 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -329,8 +329,7 @@ EXPORT_SYMBOL(get_cmos_time); static void sync_cmos_clock(unsigned long dummy); -static struct timer_list sync_cmos_timer = - TIMER_INITIALIZER(sync_cmos_clock, 0, 0); +static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); static void sync_cmos_clock(unsigned long dummy) { diff --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c index cb5d936304672..bd5d134e9f123 100644 --- a/arch/m68k/amiga/amisound.c +++ b/arch/m68k/amiga/amisound.c @@ -63,7 +63,7 @@ void __init amiga_init_sound(void) } static void nosound( unsigned long ignored ); -static struct timer_list sound_timer = TIMER_INITIALIZER(nosound, 0, 0); +static DEFINE_TIMER(sound_timer, nosound, 0, 0); void amiga_mksound( unsigned int hz, unsigned int ticks ) { diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c index 44c5cd2ad6a8d..8f0640847ad2b 100644 --- a/arch/m68k/mac/macboing.c +++ b/arch/m68k/mac/macboing.c @@ -56,8 +56,7 @@ static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ); /* * our timer to start/continue/stop the bell */ -static struct timer_list mac_sound_timer = - TIMER_INITIALIZER(mac_nosound, 0, 0); +static DEFINE_TIMER(mac_sound_timer, mac_nosound, 0, 0); /* * Sort of initialize the sound chip (called from mac_mksound on the first diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c index 89fe0ceeaa402..2ca9ec7ec3a7b 100644 --- a/arch/ppc/8xx_io/cs4218_tdm.c +++ b/arch/ppc/8xx_io/cs4218_tdm.c @@ -1380,7 +1380,7 @@ static void cs_nosound(unsigned long xx) spin_unlock_irqrestore(&cs4218_lock, flags); } -static struct timer_list beep_timer = TIMER_INITIALIZER(cs_nosound, 0, 0); +static DEFINE_TIMER(beep_timer, cs_nosound, 0, 0); }; static void cs_mksound(unsigned int hz, unsigned int ticks) diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c index c0a37d98b4f3d..048542341204e 100644 --- a/drivers/acorn/block/fd1772.c +++ b/drivers/acorn/block/fd1772.c @@ -376,19 +376,15 @@ static void do_fd_request(request_queue_t *); /************************* End of Prototypes **************************/ -static struct timer_list motor_off_timer = - TIMER_INITIALIZER(fd_motor_off_timer, 0, 0); +static DEFINE_TIMER(motor_off_timer, fd_motor_off_timer, 0, 0); #ifdef TRACKBUFFER -static struct timer_list readtrack_timer = - TIMER_INITIALIZER(fd_readtrack_check, 0, 0); +static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0); #endif -static struct timer_list timeout_timer = - TIMER_INITIALIZER(fd_times_out, 0, 0); +static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0); -static struct timer_list fd_timer = - TIMER_INITIALIZER(check_change, 0, 0); +static DEFINE_TIMER(fd_timer, check_change, 0, 0); /* DAG: Haven't got a clue what this is? */ int stdma_islocked(void) diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c index b8c260ed4b27a..0aabfc2a59d9e 100644 --- a/drivers/atm/idt77105.c +++ b/drivers/atm/idt77105.c @@ -50,10 +50,8 @@ static void idt77105_stats_timer_func(unsigned long); static void idt77105_restart_timer_func(unsigned long); -static struct timer_list stats_timer = - TIMER_INITIALIZER(idt77105_stats_timer_func, 0, 0); -static struct timer_list restart_timer = - TIMER_INITIALIZER(idt77105_restart_timer_func, 0, 0); +static DEFINE_TIMER(stats_timer, idt77105_stats_timer_func, 0, 0); +static DEFINE_TIMER(restart_timer, idt77105_restart_timer_func, 0, 0); static int start_timer = 1; static struct idt77105_priv *idt77105_all = NULL; diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index a43575acb2c1d..2e2e50e1167a3 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -79,7 +79,7 @@ static IADEV *ia_dev[8]; static struct atm_dev *_ia_dev[8]; static int iadev_count; static void ia_led_timer(unsigned long arg); -static struct timer_list ia_timer = TIMER_INITIALIZER(ia_led_timer, 0, 0); +static DEFINE_TIMER(ia_timer, ia_led_timer, 0, 0); static int IA_TX_BUF = DFL_TX_BUFFERS, IA_TX_BUF_SZ = DFL_TX_BUF_SZ; static int IA_RX_BUF = DFL_RX_BUFFERS, IA_RX_BUF_SZ = DFL_RX_BUF_SZ; static uint IADebugFlag = /* IF_IADBG_ERR | IF_IADBG_CBR| IF_IADBG_INIT_ADAPTER diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index ce933de480849..0e1f34fef0c83 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -371,7 +371,7 @@ static int acsi_revalidate (struct gendisk *disk); /************************* End of Prototypes **************************/ -struct timer_list acsi_timer = TIMER_INITIALIZER(acsi_times_out, 0, 0); +DEFINE_TIMER(acsi_timer, acsi_times_out, 0, 0); #ifdef CONFIG_ATARI_SLM diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c index e3be8c31a74cc..a5c1c8e871ec3 100644 --- a/drivers/block/acsi_slm.c +++ b/drivers/block/acsi_slm.c @@ -268,7 +268,7 @@ static int slm_get_pagesize( int device, int *w, int *h ); /************************* End of Prototypes **************************/ -static struct timer_list slm_timer = TIMER_INITIALIZER(slm_test_ready, 0, 0); +static DEFINE_TIMER(slm_timer, slm_test_ready, 0, 0); static struct file_operations slm_fops = { .owner = THIS_MODULE, diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index db05a5a99f354..22bda05fc693f 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -371,16 +371,10 @@ static int floppy_release( struct inode * inode, struct file * filp ); /************************* End of Prototypes **************************/ -static struct timer_list motor_off_timer = - TIMER_INITIALIZER(fd_motor_off_timer, 0, 0); -static struct timer_list readtrack_timer = - TIMER_INITIALIZER(fd_readtrack_check, 0, 0); - -static struct timer_list timeout_timer = - TIMER_INITIALIZER(fd_times_out, 0, 0); - -static struct timer_list fd_timer = - TIMER_INITIALIZER(check_change, 0, 0); +static DEFINE_TIMER(motor_off_timer, fd_motor_off_timer, 0, 0); +static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0); +static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0); +static DEFINE_TIMER(fd_timer, check_change, 0, 0); static inline void start_motor_off_timer(void) { diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 888dad5eef349..00895477155e6 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -628,7 +628,7 @@ static inline void debugt(const char *message) { } #endif /* DEBUGT */ typedef void (*timeout_fn) (unsigned long); -static struct timer_list fd_timeout = TIMER_INITIALIZER(floppy_shutdown, 0, 0); +static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0); static const char *timeout_message; @@ -1012,7 +1012,7 @@ static void schedule_bh(void (*handler) (void)) schedule_work(&floppy_work); } -static struct timer_list fd_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(fd_timer, NULL, 0, 0); static void cancel_activity(void) { diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 29548784cb7b1..29d1518be72a1 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -99,8 +99,7 @@ static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int); static int no_int_yet; static int ps2esdi_drives; static u_short io_base; -static struct timer_list esdi_timer = - TIMER_INITIALIZER(ps2esdi_reset_timer, 0, 0); +static DEFINE_TIMER(esdi_timer, ps2esdi_reset_timer, 0, 0); static int reset_status; static int ps2esdi_slot = -1; static int tp720esdi = 0; /* Is it Integrated ESDI of ThinkPad-720? */ diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index 43bf1e5dc38a4..ce4a1ce59d6a2 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -297,7 +297,7 @@ static char azt_auto_eject = AZT_AUTO_EJECT; static int AztTimeout, AztTries; static DECLARE_WAIT_QUEUE_HEAD(azt_waitq); -static struct timer_list delay_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(delay_timer, NULL, 0, 0); static struct azt_DiskInfo DiskInfo; static struct azt_Toc Toc[MAX_TRACKS]; diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c index 7eac10e63b235..ad5464ab99bce 100644 --- a/drivers/cdrom/gscd.c +++ b/drivers/cdrom/gscd.c @@ -146,7 +146,7 @@ static int AudioStart_f; static int AudioEnd_m; static int AudioEnd_f; -static struct timer_list gscd_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(gscd_timer, NULL, 0, 0); static DEFINE_SPINLOCK(gscd_lock); static struct request_queue *gscd_queue; diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c index 351a01dd503a3..0b0eab4f40fa9 100644 --- a/drivers/cdrom/optcd.c +++ b/drivers/cdrom/optcd.c @@ -264,7 +264,7 @@ static inline int flag_low(int flag, unsigned long timeout) static int sleep_timeout; /* max # of ticks to sleep */ static DECLARE_WAIT_QUEUE_HEAD(waitq); static void sleep_timer(unsigned long data); -static struct timer_list delay_timer = TIMER_INITIALIZER(sleep_timer, 0, 0); +static DEFINE_TIMER(delay_timer, sleep_timer, 0, 0); static DEFINE_SPINLOCK(optcd_lock); static struct request_queue *opt_queue; diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index 452d34675159c..30a8977553617 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -742,13 +742,10 @@ static struct sbpcd_drive *current_drive = D_S; unsigned long cli_sti; /* for saving the processor flags */ #endif /*==========================================================================*/ -static struct timer_list delay_timer = - TIMER_INITIALIZER(mark_timeout_delay, 0, 0); -static struct timer_list data_timer = - TIMER_INITIALIZER(mark_timeout_data, 0, 0); +static DEFINE_TIMER(delay_timer, mark_timeout_delay, 0, 0); +static DEFINE_TIMER(data_timer, mark_timeout_data, 0, 0); #if 0 -static struct timer_list audio_timer = - TIMER_INITIALIZER(mark_timeout_audio, 0, 0); +static DEFINE_TIMER(audio_timer, mark_timeout_audio, 0, 0); #endif /*==========================================================================*/ /* diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c index 4e7a342ec36ff..74b1cadbf161d 100644 --- a/drivers/cdrom/sjcd.c +++ b/drivers/cdrom/sjcd.c @@ -151,7 +151,7 @@ static struct sjcd_stat statistic; /* * Timer. */ -static struct timer_list sjcd_delay_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(sjcd_delay_timer, NULL, 0, 0); #define SJCD_SET_TIMER( func, tmout ) \ ( sjcd_delay_timer.expires = jiffies+tmout, \ diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 6a5337bf09368..cf4c3648463db 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -865,7 +865,7 @@ static void cyz_poll(unsigned long); static long cyz_polling_cycle = CZ_DEF_POLL; static int cyz_timeron = 0; -static struct timer_list cyz_timerlist = TIMER_INITIALIZER(cyz_poll, 0, 0); +static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0); #else /* CONFIG_CYZ_INTR */ static void cyz_rx_restart(unsigned long); diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index 81d811edf3c58..a54bc93353af1 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -149,8 +149,7 @@ static unsigned long long hangcheck_tsc, hangcheck_tsc_margin; static void hangcheck_fire(unsigned long); -static struct timer_list hangcheck_ticktock = - TIMER_INITIALIZER(hangcheck_fire, 0, 0); +static DEFINE_TIMER(hangcheck_ticktock, hangcheck_fire, 0, 0); static void hangcheck_fire(unsigned long data) diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 066d7b5cb76d4..9e4e26aef94ea 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -254,7 +254,7 @@ static unsigned long bh_counter = 0; * selected, the board is serviced periodically to see if anything needs doing. */ #define POLL_TIMEOUT (jiffies + 1) -static struct timer_list PollTimer = TIMER_INITIALIZER(ip2_poll, 0, 0); +static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0); static char TimerOn; #ifdef IP2DEBUG_TRACE diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 52a073eee201d..9c19e5435a11f 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -780,7 +780,7 @@ static struct file_operations stli_fsiomem = { * much cheaper on host cpu than using interrupts. It turns out to * not increase character latency by much either... */ -static struct timer_list stli_timerlist = TIMER_INITIALIZER(stli_poll, 0, 0); +static DEFINE_TIMER(stli_timerlist, stli_poll, 0, 0); static int stli_timeron; diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 523fd3c8bbaa7..1745065d8f789 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -233,8 +233,7 @@ static void kd_nosound(unsigned long ignored) } } -static struct timer_list kd_mksound_timer = - TIMER_INITIALIZER(kd_nosound, 0, 0); +static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); void kd_mksound(unsigned int hz, unsigned int ticks) { diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index c9b301dccec36..7fc2188386d96 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -59,7 +59,7 @@ static unsigned long mixcomwd_opened; /* long req'd for setbit --RR */ static int watchdog_port; static int mixcomwd_timer_alive; -static struct timer_list mixcomwd_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(mixcomwd_timer, NULL, 0, 0); static char expect_close; static int nowayout = WATCHDOG_NOWAYOUT; diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c index 1798ce7262c9b..0095384ff4542 100644 --- a/drivers/net/atari_bionet.c +++ b/drivers/net/atari_bionet.c @@ -155,7 +155,7 @@ static int bionet_close(struct net_device *dev); static struct net_device_stats *net_get_stats(struct net_device *dev); static void bionet_tick(unsigned long); -static struct timer_list bionet_timer = TIMER_INITIALIZER(bionet_tick, 0, 0); +static DEFINE_TIMER(bionet_timer, bionet_tick, 0, 0); #define STRAM_ADDR(a) (((a) & 0xff000000) == 0) diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c index 81c362c8cb973..8b997809f9de2 100644 --- a/drivers/net/atari_pamsnet.c +++ b/drivers/net/atari_pamsnet.c @@ -165,7 +165,7 @@ static void pamsnet_tick(unsigned long); static irqreturn_t pamsnet_intr(int irq, void *data, struct pt_regs *fp); -static struct timer_list pamsnet_timer = TIMER_INITIALIZER(pamsnet_tick, 0, 0); +static DEFINE_TIMER(pamsnet_timer, pamsnet_tick, 0, 0); #define STRAM_ADDR(a) (((a) & 0xff000000) == 0) diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 442670860fca2..b68b9cad76e9d 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -384,8 +384,8 @@ static unsigned int mdio_phy_addr; /* Transciever address */ static unsigned int network_tr_ctrl_shadow = 0; /* Network speed indication. */ -static struct timer_list speed_timer = TIMER_INITIALIZER(NULL, 0, 0); -static struct timer_list clear_led_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(speed_timer, NULL, 0, 0); +static DEFINE_TIMER(clear_led_timer, NULL, 0, 0); static int current_speed; /* Speed read from transceiver */ static int current_speed_selection; /* Speed selected by user */ static unsigned long led_next_time; @@ -393,7 +393,7 @@ static int led_active; static int rx_queue_len; /* Duplex */ -static struct timer_list duplex_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(duplex_timer, NULL, 0, 0); static int full_duplex; static enum duplex current_duplex; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 41213ef602dc7..f52ee3162c51d 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -170,7 +170,7 @@ static char ax25_bcast[7] = static char ax25_test[7] = {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; -static struct timer_list yam_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(yam_timer, NULL, 0, 0); /* --------------------------------------------------------------------- */ diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c index d96cc47de5668..672f9f2b21634 100644 --- a/drivers/sbus/char/aurora.c +++ b/drivers/sbus/char/aurora.c @@ -871,8 +871,7 @@ static irqreturn_t aurora_interrupt(int irq, void * dev_id, struct pt_regs * reg #ifdef AURORA_INT_DEBUG static void aurora_timer (unsigned long ignored); -static struct timer_list aurora_poll_timer = - TIMER_INITIALIZER(aurora_timer, 0, 0); +static DEFINE_TIMER(aurora_poll_timer, aurora_timer, 0, 0); static void aurora_timer (unsigned long ignored) diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c index 623082d3a83f5..c89da7d5b6dff 100644 --- a/drivers/scsi/pluto.c +++ b/drivers/scsi/pluto.c @@ -95,8 +95,7 @@ int __init pluto_detect(Scsi_Host_Template *tpnt) int i, retry, nplutos; fc_channel *fc; Scsi_Device dev; - struct timer_list fc_timer = - TIMER_INITIALIZER(pluto_detect_timeout, 0, 0); + DEFINE_TIMER(fc_timer, pluto_detect_timeout, 0, 0); tpnt->proc_name = "pluto"; fcscount = 0; diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 81f8f6b7fdce1..a8267cf17db46 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -178,8 +178,8 @@ static __u8 root_hub_hub_des[] = 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ }; -static struct timer_list bulk_start_timer = TIMER_INITIALIZER(NULL, 0, 0); -static struct timer_list bulk_eot_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(bulk_start_timer, NULL, 0, 0); +static DEFINE_TIMER(bulk_eot_timer, NULL, 0, 0); /* We want the start timer to expire before the eot timer, because the former might start traffic, thus making it unnecessary for the latter to time out. */ diff --git a/include/linux/timer.h b/include/linux/timer.h index 221f81ac2002b..3340f3bd135da 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -32,6 +32,10 @@ extern struct timer_base_s __init_timer_base; .magic = TIMER_MAGIC, \ } +#define DEFINE_TIMER(_name, _function, _expires, _data) \ + struct timer_list _name = \ + TIMER_INITIALIZER(_function, _expires, _data) + void fastcall init_timer(struct timer_list * timer); /*** diff --git a/mm/page-writeback.c b/mm/page-writeback.c index a6329fa8f862d..0166ea15c9ee8 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -368,10 +368,8 @@ int wakeup_pdflush(long nr_pages) static void wb_timer_fn(unsigned long unused); static void laptop_timer_fn(unsigned long unused); -static struct timer_list wb_timer = - TIMER_INITIALIZER(wb_timer_fn, 0, 0); -static struct timer_list laptop_mode_wb_timer = - TIMER_INITIALIZER(laptop_timer_fn, 0, 0); +static DEFINE_TIMER(wb_timer, wb_timer_fn, 0, 0); +static DEFINE_TIMER(laptop_mode_wb_timer, laptop_timer_fn, 0, 0); /* * Periodic writeback of "old" data. diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 17a81ebe7e6eb..526d9531411f5 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -105,7 +105,7 @@ extern void mpc_proc_clean(void); struct mpoa_client *mpcs = NULL; /* FIXME */ static struct atm_mpoa_qos *qos_head = NULL; -static struct timer_list mpc_timer = TIMER_INITIALIZER(NULL, 0, 0); +static DEFINE_TIMER(mpc_timer, NULL, 0, 0); static struct mpoa_client *find_mpc_by_itfnum(int itf) diff --git a/net/core/dst.c b/net/core/dst.c index 334790da9f160..470c05bc4cb2b 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -39,8 +39,7 @@ static unsigned long dst_gc_timer_inc = DST_GC_MAX; static void dst_run_gc(unsigned long); static void ___dst_free(struct dst_entry * dst); -static struct timer_list dst_gc_timer = - TIMER_INITIALIZER(dst_run_gc, DST_GC_MIN, 0); +static DEFINE_TIMER(dst_gc_timer, dst_run_gc, DST_GC_MIN, 0); static void dst_run_gc(unsigned long dummy) { diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 2c915f305be37..3407f190afe88 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -117,8 +117,7 @@ static struct dn_rt_hash_bucket *dn_rt_hash_table; static unsigned dn_rt_hash_mask; static struct timer_list dn_route_timer; -static struct timer_list dn_rt_flush_timer = - TIMER_INITIALIZER(dn_run_flush, 0, 0); +static DEFINE_TIMER(dn_rt_flush_timer, dn_run_flush, 0, 0); int decnet_dst_gc_interval = 2; static struct dst_ops dn_dst_ops = { diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index f84ba9c96551e..2fc3fd38924f2 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -100,8 +100,7 @@ DEFINE_SPINLOCK(inet_peer_unused_lock); #define PEER_MAX_CLEANUP_WORK 30 static void peer_check_expire(unsigned long dummy); -static struct timer_list peer_periodic_timer = - TIMER_INITIALIZER(peer_check_expire, 0, 0); +static DEFINE_TIMER(peer_periodic_timer, peer_check_expire, 0, 0); /* Exported for sysctl_net_ipv4. */ int inet_peer_gc_mintime = 10 * HZ, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6d6fb74f3b529..2fea3f4402a0e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -123,8 +123,7 @@ DEFINE_RWLOCK(addrconf_lock); static void addrconf_verify(unsigned long); -static struct timer_list addr_chk_timer = - TIMER_INITIALIZER(addrconf_verify, 0, 0); +static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0); static DEFINE_SPINLOCK(addrconf_verify_lock); static void addrconf_join_anycast(struct inet6_ifaddr *ifp); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 16af874c9e8f1..4fcc5a7acf6e4 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -92,7 +92,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); static __u32 rt_sernum; -static struct timer_list ip6_fib_timer = TIMER_INITIALIZER(fib6_run_gc, 0, 0); +static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0); struct fib6_walker_t fib6_walker_list = { .prev = &fib6_walker_list, diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index a7db762de14a9..f841bde30c184 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -50,7 +50,7 @@ static atomic_t fl_size = ATOMIC_INIT(0); static struct ip6_flowlabel *fl_ht[FL_HASH_MASK+1]; static void ip6_fl_gc(unsigned long dummy); -static struct timer_list ip6_fl_gc_timer = TIMER_INITIALIZER(ip6_fl_gc, 0, 0); +static DEFINE_TIMER(ip6_fl_gc_timer, ip6_fl_gc, 0, 0); /* FL hash table lock: it protects only of GC */ diff --git a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c index 165b2abce1108..e856ae1b360a1 100644 --- a/net/netrom/nr_loopback.c +++ b/net/netrom/nr_loopback.c @@ -17,7 +17,7 @@ static void nr_loopback_timer(unsigned long); static struct sk_buff_head loopback_queue; -static struct timer_list loopback_timer = TIMER_INITIALIZER(nr_loopback_timer, 0, 0); +static DEFINE_TIMER(loopback_timer, nr_loopback_timer, 0, 0); void __init nr_loopback_init(void) { diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 737681cb9a928..31570b9a6e9aa 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1194,7 +1194,7 @@ EXPORT_SYMBOL(psched_time_base); * with 32-bit get_cycles(). Safe up to 4GHz CPU. */ static void psched_tick(unsigned long); -static struct timer_list psched_timer = TIMER_INITIALIZER(psched_tick, 0, 0); +static DEFINE_TIMER(psched_timer, psched_tick, 0, 0); static void psched_tick(unsigned long dummy) { diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c index b2676fa34630c..6982556ded56f 100644 --- a/sound/oss/midibuf.c +++ b/sound/oss/midibuf.c @@ -50,7 +50,7 @@ static struct midi_parms parms[MAX_MIDI_DEV]; static void midi_poll(unsigned long dummy); -static struct timer_list poll_timer = TIMER_INITIALIZER(midi_poll, 0, 0); +static DEFINE_TIMER(poll_timer, midi_poll, 0, 0); static volatile int open_devs; static DEFINE_SPINLOCK(lock); diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index a686be936aff4..95fa81e26de21 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -681,8 +681,7 @@ static void do_sequencer_timer(unsigned long dummy) } -static struct timer_list seq_timer = - TIMER_INITIALIZER(do_sequencer_timer, 0, 0); +static DEFINE_TIMER(seq_timer, do_sequencer_timer, 0, 0); void request_sound_timer(int count) { diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c index 6afe29b763b74..c9d04518b1722 100644 --- a/sound/oss/sys_timer.c +++ b/sound/oss/sys_timer.c @@ -28,8 +28,7 @@ static unsigned long prev_event_time; static void poll_def_tmr(unsigned long dummy); static DEFINE_SPINLOCK(lock); - -static struct timer_list def_tmr = TIMER_INITIALIZER(poll_def_tmr, 0, 0); +static DEFINE_TIMER(def_tmr, poll_def_tmr, 0, 0); static unsigned long tmr2ticks(int tmr_value) diff --git a/sound/oss/uart6850.c b/sound/oss/uart6850.c index be00cf128651e..74ae75f9e2dc4 100644 --- a/sound/oss/uart6850.c +++ b/sound/oss/uart6850.c @@ -78,8 +78,7 @@ static void (*midi_input_intr) (int dev, unsigned char data); static void poll_uart6850(unsigned long dummy); -static struct timer_list uart6850_timer = - TIMER_INITIALIZER(poll_uart6850, 0, 0); +static DEFINE_TIMER(uart6850_timer, poll_uart6850, 0, 0); static void uart6850_input_loop(void) { -- GitLab From a9f6a0dd54efea2a5d57a27e6c232f9197c25154 Mon Sep 17 00:00:00 2001 From: Ingo Molnar <mingo@elte.hu> Date: Fri, 9 Sep 2005 13:10:41 -0700 Subject: [PATCH 282/563] [PATCH] more SPIN_LOCK_UNLOCKED -> DEFINE_SPINLOCK conversions This converts the final 20 DEFINE_SPINLOCK holdouts. (another 580 places are already using DEFINE_SPINLOCK). Build tested on x86. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/arm/mach-pxa/corgi_ssp.c | 2 +- arch/ia64/kernel/perfmon.c | 2 +- arch/ia64/sn/kernel/xpnet.c | 2 +- arch/mips/kernel/genrtc.c | 2 +- arch/mips/kernel/i8259.c | 2 +- arch/ppc/platforms/hdpu.c | 2 +- arch/ppc/syslib/mv64x60.c | 2 +- arch/ppc/syslib/qspan_pci.c | 2 +- arch/ppc64/kernel/pmc.c | 2 +- arch/sparc/lib/atomic32.c | 2 +- drivers/net/mv643xx_eth.c | 2 +- drivers/parisc/iosapic.c | 2 +- drivers/scsi/ch.c | 2 +- drivers/video/geode/display_gx1.c | 2 +- fs/xfs/support/ktrace.c | 2 +- net/core/netpoll.c | 4 ++-- net/core/pktgen.c | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c index 8ccffba0018fa..366a9bde3d8be 100644 --- a/arch/arm/mach-pxa/corgi_ssp.c +++ b/arch/arm/mach-pxa/corgi_ssp.c @@ -22,7 +22,7 @@ #include <asm/arch/corgi.h> #include <asm/arch/pxa-regs.h> -static spinlock_t corgi_ssp_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(corgi_ssp_lock); static struct ssp_dev corgi_ssp_dev; static struct ssp_state corgi_ssp_state; diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 4ad97b3b39dcc..1650353e3f77e 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -497,7 +497,7 @@ typedef struct { static pfm_stats_t pfm_stats[NR_CPUS]; static pfm_session_t pfm_sessions; /* global sessions information */ -static spinlock_t pfm_alt_install_check = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(pfm_alt_install_check); static pfm_intr_handler_desc_t *pfm_alt_intr_handler; static struct proc_dir_entry *perfmon_dir; diff --git a/arch/ia64/sn/kernel/xpnet.c b/arch/ia64/sn/kernel/xpnet.c index d0c2c114a459a..e5c6d3c0a8e9a 100644 --- a/arch/ia64/sn/kernel/xpnet.c +++ b/arch/ia64/sn/kernel/xpnet.c @@ -130,7 +130,7 @@ struct net_device *xpnet_device; */ static u64 xpnet_broadcast_partitions; /* protect above */ -static spinlock_t xpnet_broadcast_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(xpnet_broadcast_lock); /* * Since the Block Transfer Engine (BTE) is being used for the transfer diff --git a/arch/mips/kernel/genrtc.c b/arch/mips/kernel/genrtc.c index 288bf51ad4ecd..71416e7bbbaa3 100644 --- a/arch/mips/kernel/genrtc.c +++ b/arch/mips/kernel/genrtc.c @@ -14,7 +14,7 @@ #include <asm/rtc.h> #include <asm/time.h> -static spinlock_t mips_rtc_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(mips_rtc_lock); unsigned int get_rtc_time(struct rtc_time *time) { diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 7eec7568bfea5..447759201d1dd 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -31,7 +31,7 @@ void disable_8259A_irq(unsigned int irq); * moves to arch independent land */ -spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; +spinlock_t DEFINE_SPINLOCK(i8259A_lock); static void end_8259A_irq (unsigned int irq) { diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c index b659d7b3d7477..ff3796860123a 100644 --- a/arch/ppc/platforms/hdpu.c +++ b/arch/ppc/platforms/hdpu.c @@ -58,7 +58,7 @@ static void parse_bootinfo(unsigned long r3, static void hdpu_set_l1pe(void); static void hdpu_cpustate_set(unsigned char new_state); #ifdef CONFIG_SMP -static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(timebase_lock); static unsigned int timebase_upper = 0, timebase_lower = 0; extern int smp_tb_synchronized; diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c index 6262b11f366f7..839f8872826f4 100644 --- a/arch/ppc/syslib/mv64x60.c +++ b/arch/ppc/syslib/mv64x60.c @@ -31,7 +31,7 @@ u8 mv64x60_pci_exclude_bridge = 1; -spinlock_t mv64x60_lock = SPIN_LOCK_UNLOCKED; +DEFINE_SPINLOCK(mv64x60_lock); static phys_addr_t mv64x60_bridge_pbase; static void *mv64x60_bridge_vbase; diff --git a/arch/ppc/syslib/qspan_pci.c b/arch/ppc/syslib/qspan_pci.c index 57f4ed5e5ae1a..0970b5d303915 100644 --- a/arch/ppc/syslib/qspan_pci.c +++ b/arch/ppc/syslib/qspan_pci.c @@ -94,7 +94,7 @@ #define mk_config_type1(bus, dev, offset) \ mk_config_addr(bus, dev, offset) | 1; -static spinlock_t pcibios_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(pcibios_lock); int qspan_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) diff --git a/arch/ppc64/kernel/pmc.c b/arch/ppc64/kernel/pmc.c index cdfec7438d013..63d9481c3ec2f 100644 --- a/arch/ppc64/kernel/pmc.c +++ b/arch/ppc64/kernel/pmc.c @@ -26,7 +26,7 @@ static void dummy_perf(struct pt_regs *regs) mtspr(SPRN_MMCR0, mmcr0); } -static spinlock_t pmc_owner_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(pmc_owner_lock); static void *pmc_owner_caller; /* mostly for debugging */ perf_irq_t perf_irq = dummy_perf; diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c index 19724c5800a79..2e64e8c3e8e54 100644 --- a/arch/sparc/lib/atomic32.c +++ b/arch/sparc/lib/atomic32.c @@ -20,7 +20,7 @@ spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] = { #else /* SMP */ -static spinlock_t dummy = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(dummy); #define ATOMIC_HASH_SIZE 1 #define ATOMIC_HASH(a) (&dummy) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 7c9dbc8c9423a..25c9a99c377b1 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -94,7 +94,7 @@ static char mv643xx_driver_version[] = "1.0"; static void __iomem *mv643xx_eth_shared_base; /* used to protect MV643XX_ETH_SMI_REG, which is shared across ports */ -static spinlock_t mv643xx_eth_phy_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(mv643xx_eth_phy_lock); static inline u32 mv_read(int offset) { diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 91df0bf181ddf..7a57c1b8373f0 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -215,7 +215,7 @@ static inline void iosapic_write(void __iomem *iosapic, unsigned int reg, u32 va #define IOSAPIC_IRDT_ID_EID_SHIFT 0x10 -static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(iosapic_lock); static inline void iosapic_eoi(void __iomem *addr, unsigned int data) { diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index bd0e1b6be1ea6..13ecd0c474043 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -116,7 +116,7 @@ typedef struct { } scsi_changer; static LIST_HEAD(ch_devlist); -static spinlock_t ch_devlist_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(ch_devlist_lock); static int ch_devcount; static struct scsi_driver ch_template = diff --git a/drivers/video/geode/display_gx1.c b/drivers/video/geode/display_gx1.c index f4983879fcc4b..926d53eeb5495 100644 --- a/drivers/video/geode/display_gx1.c +++ b/drivers/video/geode/display_gx1.c @@ -22,7 +22,7 @@ #include "geodefb.h" #include "display_gx1.h" -static spinlock_t gx1_conf_reg_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(gx1_conf_reg_lock); static u8 gx1_read_conf_reg(u8 reg) { diff --git a/fs/xfs/support/ktrace.c b/fs/xfs/support/ktrace.c index 3dae14c8c55a1..fa8394f9437d4 100644 --- a/fs/xfs/support/ktrace.c +++ b/fs/xfs/support/ktrace.c @@ -170,7 +170,7 @@ ktrace_enter( void *val14, void *val15) { - static lock_t wrap_lock = SPIN_LOCK_UNLOCKED; + static DEFINE_SPINLOCK(wrap_lock); unsigned long flags; int index; ktrace_entry_t *ktep; diff --git a/net/core/netpoll.c b/net/core/netpoll.c index a1a9a7abff509..5265dfd699284 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -645,10 +645,10 @@ int netpoll_setup(struct netpoll *np) npinfo->rx_flags = 0; npinfo->rx_np = NULL; - npinfo->poll_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&npinfo->poll_lock); npinfo->poll_owner = -1; npinfo->tries = MAX_RETRIES; - npinfo->rx_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&npinfo->rx_lock); } else npinfo = ndev->npinfo; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 8eb083b6041a7..b3ad49fa7d787 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -503,7 +503,7 @@ static int pg_delay_d = 0; static int pg_clone_skb_d = 0; static int debug = 0; -static spinlock_t _thread_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(_thread_lock); static struct pktgen_thread *pktgen_threads = NULL; static char module_fname[128]; -- GitLab From 18fb9442576c79fc2f4bca1fd90c3aa4d1115e97 Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" <viro@ZenIV.linux.org.uk> Date: Fri, 9 Sep 2005 20:14:05 +0100 Subject: [PATCH 283/563] [PATCH] trivial __user annotations (ipmi) Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/ipmi/ipmi_devintf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 883ac4352be49..a09ff10806874 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -735,7 +735,8 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, case COMPAT_IPMICTL_RECEIVE_MSG: case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC: { - struct ipmi_recv *precv64, recv64; + struct ipmi_recv __user *precv64; + struct ipmi_recv recv64; if (get_compat_ipmi_recv(&recv64, compat_ptr(arg))) return -EFAULT; @@ -748,7 +749,7 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, ((cmd == COMPAT_IPMICTL_RECEIVE_MSG) ? IPMICTL_RECEIVE_MSG : IPMICTL_RECEIVE_MSG_TRUNC), - (long) precv64); + (unsigned long) precv64); if (rc != 0) return rc; -- GitLab From 21b29229086bcaf14c02b160c253095f3bb95f99 Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" <viro@ZenIV.linux.org.uk> Date: Fri, 9 Sep 2005 20:26:01 +0100 Subject: [PATCH 284/563] [PATCH] trivial __user cleanup (video1394) Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/ieee1394/video1394.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index 06759b36afea0..9d6facf2f78f5 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -883,7 +883,7 @@ static int __video1394_ioctl(struct file *file, v.channel); } - if (copy_to_user((void *)arg, &v, sizeof(v))) { + if (copy_to_user(argp, &v, sizeof(v))) { /* FIXME : free allocated dma resources */ return -EFAULT; } -- GitLab From 01703597ead8194b46932ba2bcda897e872e91e0 Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" <viro@ZenIV.linux.org.uk> Date: Fri, 9 Sep 2005 20:29:12 +0100 Subject: [PATCH 285/563] [PATCH] trivial __user annotations (evdev) Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/input/evdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 19c14c4beb44e..60b696e9336b8 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -509,7 +509,7 @@ do { \ int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \ for (i = 0; i < len / sizeof(compat_long_t); i++) \ - if (copy_to_user((compat_long_t*) p + i, \ + if (copy_to_user((compat_long_t __user *) p + i, \ (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \ sizeof(compat_long_t))) \ return -EFAULT; \ -- GitLab From 87162a28acceda05dadf10a8333183f6d2b55265 Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" <viro@ZenIV.linux.org.uk> Date: Fri, 9 Sep 2005 20:36:43 +0100 Subject: [PATCH 286/563] [PATCH] trivial __user annotations (md) Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 20ca80b7dc206..373ab92e367b8 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2087,7 +2087,7 @@ static int get_array_info(mddev_t * mddev, void __user * arg) return 0; } -static int get_bitmap_file(mddev_t * mddev, void * arg) +static int get_bitmap_file(mddev_t * mddev, void __user * arg) { mdu_bitmap_file_t *file = NULL; /* too big for stack allocation */ char *ptr, *buf = NULL; @@ -2781,7 +2781,7 @@ static int md_ioctl(struct inode *inode, struct file *file, goto done_unlock; case GET_BITMAP_FILE: - err = get_bitmap_file(mddev, (void *)arg); + err = get_bitmap_file(mddev, argp); goto done_unlock; case GET_DISK_INFO: -- GitLab From b95adac775aad29f79ffbbaf5db0e4d8d57f2714 Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" <viro@ZenIV.linux.org.uk> Date: Fri, 9 Sep 2005 21:42:25 +0100 Subject: [PATCH 287/563] [PATCH] trivial iomem annotations in qla2xxx/qla_dbg.c Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 72bbaa91dc777..9791496fa7884 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -1334,7 +1334,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0200000); - dmp_reg = (uint32_t *)((uint8_t *)reg + 0xFC); + dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); fw->shadow_reg[2] = RD_REG_DWORD(dmp_reg); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); -- GitLab From f64a227b6b5cc1f8cc7f6ef9cc3351343636bac9 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.(none)> Date: Fri, 9 Sep 2005 23:10:54 +0200 Subject: [PATCH 288/563] kbuild: um fix so it compile with generic asm-offsets.h support um has it own set of files for asm-offsets. So for now the gen-asm-offset macro is just duplicated in the um Makefile. This may well be the final solution since um is a bit special compared to other architectures - time will tell. Also added a dummy arch/um/kernel/asm-offsets.h file to keep kbuild happy. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/um/Makefile | 16 ++++++++++++++++ arch/um/kernel/asm-offsets.c | 1 + 2 files changed, 17 insertions(+) create mode 100644 arch/um/kernel/asm-offsets.c diff --git a/arch/um/Makefile b/arch/um/Makefile index b15f6048caae8..577b8d1cf1a6e 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -197,6 +197,22 @@ define filechk_umlconfig sed 's/ CONFIG/ UML_CONFIG/' endef +define filechk_gen-asm-offsets + (set -e; \ + echo "#ifndef __ASM_OFFSETS_H__"; \ + echo "#define __ASM_OFFSETS_H__"; \ + echo "/*"; \ + echo " * DO NOT MODIFY."; \ + echo " *"; \ + echo " * This file was generated by arch/$(ARCH)/Makefile"; \ + echo " *"; \ + echo " */"; \ + echo ""; \ + sed -ne "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}"; \ + echo ""; \ + echo "#endif" ) +endef + $(ARCH_DIR)/include/uml-config.h : include/linux/autoconf.h $(call filechk,umlconfig) diff --git a/arch/um/kernel/asm-offsets.c b/arch/um/kernel/asm-offsets.c new file mode 100644 index 0000000000000..c13a64a288f69 --- /dev/null +++ b/arch/um/kernel/asm-offsets.c @@ -0,0 +1 @@ +/* Dummy file to make kbuild happy - unused! */ -- GitLab From 35311d6478077f7bfe35c1c653193e658bf32686 Mon Sep 17 00:00:00 2001 From: Kirill Korotaev <dev@sw.ru> Date: Fri, 9 Sep 2005 13:05:53 -0700 Subject: [PATCH 289/563] [PATCH] lost fput in 32bit ioctl on x86-64 This adds a lost fput in 32bit tiocgdev ioctl on x86-64 [ chrisw: Updated to use fget_light/fput_light ] Signed-Off-By: Kirill Korotaev <dev@sw.ru> Signed-Off-By: Maxim Giryaev <gem@sw.ru> Signed-off-by: Chris Wright <chrisw@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/ia32/ia32_ioctl.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c index d259f8a6f811d..419758f19ca4f 100644 --- a/arch/x86_64/ia32/ia32_ioctl.c +++ b/arch/x86_64/ia32/ia32_ioctl.c @@ -24,17 +24,26 @@ static int tiocgdev(unsigned fd, unsigned cmd, unsigned int __user *ptr) { - struct file *file = fget(fd); + struct file *file; struct tty_struct *real_tty; + int fput_needed, ret; + file = fget_light(fd, &fput_needed); if (!file) return -EBADF; + + ret = -EINVAL; if (file->f_op->ioctl != tty_ioctl) - return -EINVAL; + goto out; real_tty = (struct tty_struct *)file->private_data; if (!real_tty) - return -EINVAL; - return put_user(new_encode_dev(tty_devnum(real_tty)), ptr); + goto out; + + ret = put_user(new_encode_dev(tty_devnum(real_tty)), ptr); + +out: + fput_light(file, fput_needed); + return ret; } #define RTC_IRQP_READ32 _IOR('p', 0x0b, unsigned int) /* Read IRQ rate */ -- GitLab From d99901d6fdfb4098b9996de89ffbbae890e08288 Mon Sep 17 00:00:00 2001 From: Kirill Korotaev <dev@sw.ru> Date: Fri, 9 Sep 2005 13:59:48 +0400 Subject: [PATCH 290/563] [PATCH] Lost sockfd_put() in routing_ioctl() This patch adds lost sockfd_put() in 32bit compat rounting_ioctl() on 64bit platforms Signed-Off-By: Kirill Korotaev <dev@sw.ru> Signed-Off-By: Maxim Giryaev <gem@sw.ru> Signed-off-By: Linus Torvalds <torvalds@osdl.org> --- fs/compat_ioctl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 155e612635f13..e28a74203f3b1 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -798,13 +798,16 @@ static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) r = (void *) &r4; } - if (ret) - return -EFAULT; + if (ret) { + ret = -EFAULT; + goto out; + } set_fs (KERNEL_DS); ret = sys_ioctl (fd, cmd, (unsigned long) r); set_fs (old_fs); +out: if (mysock) sockfd_put(mysock); -- GitLab From a4531edd75522804dd2b268d8ccc5eaa70748011 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@g5.osdl.org> Date: Fri, 9 Sep 2005 15:10:52 -0700 Subject: [PATCH 291/563] Fix up lost patch in compat_sys_select() for new RCU files world order Andrew lost this in patch reject resolution, and never noticed, since the compat code isn't in use on x86. Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/compat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/compat.c b/fs/compat.c index 8c665705c6a07..c2e0813164b45 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1619,6 +1619,7 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp char *bits; long timeout; int size, max_fdset, ret = -EINVAL; + struct fdtable *fdt; timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { @@ -1644,7 +1645,8 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp goto out_nofds; /* max_fdset can increase, so grab it once to avoid race */ - max_fdset = current->files->max_fdset; + fdt = files_fdtable(current->files); + max_fdset = fdt->max_fdset; if (n > max_fdset) n = max_fdset; -- GitLab From fbed8eee70cf7e11fbf231afafc0ccb313acc62e Mon Sep 17 00:00:00 2001 From: Hal Rosenstock <halr@voltaire.com> Date: Fri, 9 Sep 2005 15:24:04 -0700 Subject: [PATCH 292/563] [PATCH] IB: Move SA attributes to ib_sa.h SA: Move SA attributes to ib_sa.h so are accessible to more than sa_query.c. Also, remove deprecated attributes and add one missing one. Signed-off-by: Hal Rosenstock <halr@voltaire.com> Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/core/sa_query.c | 26 -------------------------- include/rdma/ib_sa.h | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 9191793c9007a..78de2dd1a4f25 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -113,32 +113,6 @@ static DEFINE_IDR(query_idr); static spinlock_t tid_lock; static u32 tid; -enum { - IB_SA_ATTR_CLASS_PORTINFO = 0x01, - IB_SA_ATTR_NOTICE = 0x02, - IB_SA_ATTR_INFORM_INFO = 0x03, - IB_SA_ATTR_NODE_REC = 0x11, - IB_SA_ATTR_PORT_INFO_REC = 0x12, - IB_SA_ATTR_SL2VL_REC = 0x13, - IB_SA_ATTR_SWITCH_REC = 0x14, - IB_SA_ATTR_LINEAR_FDB_REC = 0x15, - IB_SA_ATTR_RANDOM_FDB_REC = 0x16, - IB_SA_ATTR_MCAST_FDB_REC = 0x17, - IB_SA_ATTR_SM_INFO_REC = 0x18, - IB_SA_ATTR_LINK_REC = 0x20, - IB_SA_ATTR_GUID_INFO_REC = 0x30, - IB_SA_ATTR_SERVICE_REC = 0x31, - IB_SA_ATTR_PARTITION_REC = 0x33, - IB_SA_ATTR_RANGE_REC = 0x34, - IB_SA_ATTR_PATH_REC = 0x35, - IB_SA_ATTR_VL_ARB_REC = 0x36, - IB_SA_ATTR_MC_GROUP_REC = 0x37, - IB_SA_ATTR_MC_MEMBER_REC = 0x38, - IB_SA_ATTR_TRACE_REC = 0x39, - IB_SA_ATTR_MULTI_PATH_REC = 0x3a, - IB_SA_ATTR_SERVICE_ASSOC_REC = 0x3b -}; - #define PATH_REC_FIELD(field) \ .struct_offset_bytes = offsetof(struct ib_sa_path_rec, field), \ .struct_size_bytes = sizeof ((struct ib_sa_path_rec *) 0)->field, \ diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index 0f4f5ec85e82a..a7555c800ecf9 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -53,6 +53,31 @@ enum { IB_SA_METHOD_GET_TRACE_TBL = 0x13 }; +enum { + IB_SA_ATTR_CLASS_PORTINFO = 0x01, + IB_SA_ATTR_NOTICE = 0x02, + IB_SA_ATTR_INFORM_INFO = 0x03, + IB_SA_ATTR_NODE_REC = 0x11, + IB_SA_ATTR_PORT_INFO_REC = 0x12, + IB_SA_ATTR_SL2VL_REC = 0x13, + IB_SA_ATTR_SWITCH_REC = 0x14, + IB_SA_ATTR_LINEAR_FDB_REC = 0x15, + IB_SA_ATTR_RANDOM_FDB_REC = 0x16, + IB_SA_ATTR_MCAST_FDB_REC = 0x17, + IB_SA_ATTR_SM_INFO_REC = 0x18, + IB_SA_ATTR_LINK_REC = 0x20, + IB_SA_ATTR_GUID_INFO_REC = 0x30, + IB_SA_ATTR_SERVICE_REC = 0x31, + IB_SA_ATTR_PARTITION_REC = 0x33, + IB_SA_ATTR_PATH_REC = 0x35, + IB_SA_ATTR_VL_ARB_REC = 0x36, + IB_SA_ATTR_MC_MEMBER_REC = 0x38, + IB_SA_ATTR_TRACE_REC = 0x39, + IB_SA_ATTR_MULTI_PATH_REC = 0x3a, + IB_SA_ATTR_SERVICE_ASSOC_REC = 0x3b, + IB_SA_ATTR_INFORM_INFO_REC = 0xf3 +}; + enum ib_sa_selector { IB_SA_GTE = 0, IB_SA_LTE = 1, -- GitLab From f0eca9626c6becb6fc56106b2e4287c6c784af3d Mon Sep 17 00:00:00 2001 From: Daniel Ritz <daniel.ritz@gmx.ch> Date: Fri, 9 Sep 2005 00:57:14 +0200 Subject: [PATCH 293/563] [PATCH] Update PCI IOMEM allocation start This fixes the problem with "Averatec 6240 pcmcia_socket0: unable to apply power", which was due to the CardBus IOMEM register region being allocated at an address that was actually inside the RAM window that had been reserved for video frame-buffers in an UMA setup. The BIOS _should_ have marked that region reserved in the e820 memory descriptor tables, but did not. It is fixed by rounding up the default starting address of PCI memory allocations, so that we leave a bigger gap after the final known memory location. The amount of rounding depends on how big the unused memory gap is that we can allocate IOMEM from. Based on example code by Linus. Acked-by: Greg KH <greg@kroah.com> Acked-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/kernel/setup.c | 16 ++++++++-------- arch/x86_64/kernel/e820.c | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index fa0c69eb937a0..f3d808451d253 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -1300,7 +1300,7 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat */ static void __init register_memory(void) { - unsigned long gapstart, gapsize; + unsigned long gapstart, gapsize, round; unsigned long long last; int i; @@ -1345,14 +1345,14 @@ static void __init register_memory(void) } /* - * Start allocating dynamic PCI memory a bit into the gap, - * aligned up to the nearest megabyte. - * - * Question: should we try to pad it up a bit (do something - * like " + (gapsize >> 3)" in there too?). We now have the - * technology. + * See how much we want to round up: start off with + * rounding to the next 1MB area. */ - pci_mem_start = (gapstart + 0xfffff) & ~0xfffff; + round = 0x100000; + while ((gapsize >> 4) > round) + round += round; + /* Fun with two's complement */ + pci_mem_start = (gapstart + round) & -round; printk("Allocating PCI resources starting at %08lx (gap: %08lx:%08lx)\n", pci_mem_start, gapstart, gapsize); diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index 116ac5f53dced..bb0ae18ec02b9 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -567,7 +567,7 @@ unsigned long pci_mem_start = 0xaeedbabe; */ __init void e820_setup_gap(void) { - unsigned long gapstart, gapsize; + unsigned long gapstart, gapsize, round; unsigned long last; int i; int found = 0; @@ -604,14 +604,14 @@ __init void e820_setup_gap(void) } /* - * Start allocating dynamic PCI memory a bit into the gap, - * aligned up to the nearest megabyte. - * - * Question: should we try to pad it up a bit (do something - * like " + (gapsize >> 3)" in there too?). We now have the - * technology. + * See how much we want to round up: start off with + * rounding to the next 1MB area. */ - pci_mem_start = (gapstart + 0xfffff) & ~0xfffff; + round = 0x100000; + while ((gapsize >> 4) > round) + round += round; + /* Fun with two's complement */ + pci_mem_start = (gapstart + round) & -round; printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n", pci_mem_start, gapstart, gapsize); -- GitLab From ac5b8b6f22118620cd1133d9943b1f31dc40a913 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@g5.osdl.org> Date: Fri, 9 Sep 2005 15:42:34 -0700 Subject: [PATCH 294/563] Preempt-safe RCU file usage Fix up fs/compat.c fixes. --- fs/compat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/compat.c b/fs/compat.c index c2e0813164b45..ac3fb9ed8eeaf 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1645,8 +1645,10 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp goto out_nofds; /* max_fdset can increase, so grab it once to avoid race */ + rcu_read_lock(); fdt = files_fdtable(current->files); max_fdset = fdt->max_fdset; + rcu_read_unlock(); if (n > max_fdset) n = max_fdset; -- GitLab From 9c8550ee25e26d14a8f0fe1b761a676e23fe3cf0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@g5.osdl.org> Date: Fri, 9 Sep 2005 15:43:46 -0700 Subject: [PATCH 295/563] Remove "must_check" attributes in PCI-land Don't just irritate all other kernel developers. Fix the users first, then you can re-introduce the must-check infrastructure to avoid new cases creeping in. Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/pci.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/pci.h b/include/linux/pci.h index e5e24e13a114f..7349058ed7789 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -380,16 +380,16 @@ static inline int pci_write_config_dword(struct pci_dev *dev, int where, u32 val return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val); } -int __must_check pci_enable_device(struct pci_dev *dev); -int __must_check pci_enable_device_bars(struct pci_dev *dev, int mask); +int pci_enable_device(struct pci_dev *dev); +int pci_enable_device_bars(struct pci_dev *dev, int mask); void pci_disable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); #define HAVE_PCI_SET_MWI -int __must_check pci_set_mwi(struct pci_dev *dev); +int pci_set_mwi(struct pci_dev *dev); void pci_clear_mwi(struct pci_dev *dev); void pci_intx(struct pci_dev *dev, int enable); -int __must_check pci_set_dma_mask(struct pci_dev *dev, u64 mask); -int __must_check pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); +int pci_set_dma_mask(struct pci_dev *dev, u64 mask); +int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); int pci_assign_resource(struct pci_dev *dev, int i); void pci_restore_bars(struct pci_dev *dev); @@ -403,9 +403,9 @@ void pci_remove_rom(struct pci_dev *pdev); /* Power management related routines */ int pci_save_state(struct pci_dev *dev); int pci_restore_state(struct pci_dev *dev); -int __must_check pci_set_power_state(struct pci_dev *dev, pci_power_t state); -pci_power_t __must_check pci_choose_state(struct pci_dev *dev, pm_message_t state); -int __must_check pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable); +int pci_set_power_state(struct pci_dev *dev, pci_power_t state); +pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); +int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable); /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ void pci_bus_assign_resources(struct pci_bus *bus); -- GitLab From 2e9f7cb7869059e55cd91f5e23c6380f3763db56 Mon Sep 17 00:00:00 2001 From: Roland Dreier <roland@eddore.topspincom.com> Date: Fri, 9 Sep 2005 15:45:57 -0700 Subject: [PATCH 296/563] [PATCH] IB: Add struct for ClassPortInfo Add structure definition for ClassPortInfo format. This is needed for (at least) handling CM redirects. Signed-off-by: Roland Dreier <rolandd@cisco.com> --- include/rdma/ib_mad.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index fc6b1c18ffc69..53184a38fdf64 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -173,6 +173,27 @@ struct ib_vendor_mad { u8 data[216]; }; +struct ib_class_port_info +{ + u8 base_version; + u8 class_version; + __be16 capability_mask; + u8 reserved[3]; + u8 resp_time_value; + u8 redirect_gid[16]; + __be32 redirect_tcslfl; + __be16 redirect_lid; + __be16 redirect_pkey; + __be32 redirect_qp; + __be32 redirect_qkey; + u8 trap_gid[16]; + __be32 trap_tcslfl; + __be16 trap_lid; + __be16 trap_pkey; + __be32 trap_hlqp; + __be32 trap_qkey; +}; + /** * ib_mad_send_buf - MAD data buffer and work request for sends. * @mad: References an allocated MAD data buffer. The size of the data -- GitLab From 63aaf647529e8a56bdf31fd8f2979d4371c6a332 Mon Sep 17 00:00:00 2001 From: Roland Dreier <roland@eddore.topspincom.com> Date: Fri, 9 Sep 2005 15:55:08 -0700 Subject: [PATCH 297/563] Make sure that userspace does not retrieve stale asynchronous or completion events after destroying a CQ, QP or SRQ. We do this by sweeping the event lists before returning from a destroy calls, and then return the number of events already reported before the destroy call. This allows userspace wait until it has processed all events for an object returned from the kernel before it frees its context for the object. The ABI of the destroy CQ, destroy QP and destroy SRQ commands has to change to return the event count, so bump the ABI version from 1 to 2. The userspace libibverbs library has already been updated to handle both the old and new ABI versions. Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/core/uverbs.h | 26 +++-- drivers/infiniband/core/uverbs_cmd.c | 155 +++++++++++++++++++------- drivers/infiniband/core/uverbs_main.c | 98 ++++++++++------ include/rdma/ib_user_verbs.h | 21 +++- 4 files changed, 211 insertions(+), 89 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 180b3d4765e40..b1897bed14ad4 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -76,20 +76,28 @@ struct ib_uverbs_file { struct ib_uverbs_event_file comp_file[1]; }; -struct ib_uverbs_async_event { - struct ib_uverbs_async_event_desc desc; +struct ib_uverbs_event { + union { + struct ib_uverbs_async_event_desc async; + struct ib_uverbs_comp_event_desc comp; + } desc; struct list_head list; + struct list_head obj_list; + u32 *counter; }; -struct ib_uverbs_comp_event { - struct ib_uverbs_comp_event_desc desc; - struct list_head list; +struct ib_uevent_object { + struct ib_uobject uobject; + struct list_head event_list; + u32 events_reported; }; -struct ib_uobject_mr { - struct ib_uobject uobj; - struct page *page_list; - struct scatterlist *sg_list; +struct ib_ucq_object { + struct ib_uobject uobject; + struct list_head comp_list; + struct list_head async_list; + u32 comp_events_reported; + u32 async_events_reported; }; extern struct semaphore ib_uverbs_idr_mutex; diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index ebccf9f38af94..e91ebde464810 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -590,7 +590,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, struct ib_uverbs_create_cq cmd; struct ib_uverbs_create_cq_resp resp; struct ib_udata udata; - struct ib_uobject *uobj; + struct ib_ucq_object *uobj; struct ib_cq *cq; int ret; @@ -611,8 +611,12 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, if (!uobj) return -ENOMEM; - uobj->user_handle = cmd.user_handle; - uobj->context = file->ucontext; + uobj->uobject.user_handle = cmd.user_handle; + uobj->uobject.context = file->ucontext; + uobj->comp_events_reported = 0; + uobj->async_events_reported = 0; + INIT_LIST_HEAD(&uobj->comp_list); + INIT_LIST_HEAD(&uobj->async_list); cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, file->ucontext, &udata); @@ -622,7 +626,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, } cq->device = file->device->ib_dev; - cq->uobject = uobj; + cq->uobject = &uobj->uobject; cq->comp_handler = ib_uverbs_comp_handler; cq->event_handler = ib_uverbs_cq_event_handler; cq->cq_context = file; @@ -635,7 +639,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, } down(&ib_uverbs_idr_mutex); - ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->id); + ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->uobject.id); up(&ib_uverbs_idr_mutex); if (ret == -EAGAIN) @@ -644,11 +648,11 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, goto err_cq; spin_lock_irq(&file->ucontext->lock); - list_add_tail(&uobj->list, &file->ucontext->cq_list); + list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); spin_unlock_irq(&file->ucontext->lock); memset(&resp, 0, sizeof resp); - resp.cq_handle = uobj->id; + resp.cq_handle = uobj->uobject.id; resp.cqe = cq->cqe; if (copy_to_user((void __user *) (unsigned long) cmd.response, @@ -661,11 +665,11 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, err_list: spin_lock_irq(&file->ucontext->lock); - list_del(&uobj->list); + list_del(&uobj->uobject.list); spin_unlock_irq(&file->ucontext->lock); down(&ib_uverbs_idr_mutex); - idr_remove(&ib_uverbs_cq_idr, uobj->id); + idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id); up(&ib_uverbs_idr_mutex); err_cq: @@ -680,21 +684,27 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) { - struct ib_uverbs_destroy_cq cmd; - struct ib_cq *cq; - struct ib_uobject *uobj; - int ret = -EINVAL; + struct ib_uverbs_destroy_cq cmd; + struct ib_uverbs_destroy_cq_resp resp; + struct ib_cq *cq; + struct ib_ucq_object *uobj; + struct ib_uverbs_event *evt, *tmp; + u64 user_handle; + int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; + memset(&resp, 0, sizeof resp); + down(&ib_uverbs_idr_mutex); cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); if (!cq || cq->uobject->context != file->ucontext) goto out; - uobj = cq->uobject; + user_handle = cq->uobject->user_handle; + uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); ret = ib_destroy_cq(cq); if (ret) @@ -703,11 +713,32 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle); spin_lock_irq(&file->ucontext->lock); - list_del(&uobj->list); + list_del(&uobj->uobject.list); spin_unlock_irq(&file->ucontext->lock); + spin_lock_irq(&file->comp_file[0].lock); + list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&file->comp_file[0].lock); + + spin_lock_irq(&file->async_file.lock); + list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&file->async_file.lock); + + resp.comp_events_reported = uobj->comp_events_reported; + resp.async_events_reported = uobj->async_events_reported; + kfree(uobj); + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + out: up(&ib_uverbs_idr_mutex); @@ -721,7 +752,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, struct ib_uverbs_create_qp cmd; struct ib_uverbs_create_qp_resp resp; struct ib_udata udata; - struct ib_uobject *uobj; + struct ib_uevent_object *uobj; struct ib_pd *pd; struct ib_cq *scq, *rcq; struct ib_srq *srq; @@ -772,8 +803,10 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, attr.cap.max_recv_sge = cmd.max_recv_sge; attr.cap.max_inline_data = cmd.max_inline_data; - uobj->user_handle = cmd.user_handle; - uobj->context = file->ucontext; + uobj->uobject.user_handle = cmd.user_handle; + uobj->uobject.context = file->ucontext; + uobj->events_reported = 0; + INIT_LIST_HEAD(&uobj->event_list); qp = pd->device->create_qp(pd, &attr, &udata); if (IS_ERR(qp)) { @@ -786,7 +819,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, qp->send_cq = attr.send_cq; qp->recv_cq = attr.recv_cq; qp->srq = attr.srq; - qp->uobject = uobj; + qp->uobject = &uobj->uobject; qp->event_handler = attr.event_handler; qp->qp_context = attr.qp_context; qp->qp_type = attr.qp_type; @@ -805,17 +838,17 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, goto err_destroy; } - ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->id); + ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uobject.id); if (ret == -EAGAIN) goto retry; if (ret) goto err_destroy; - resp.qp_handle = uobj->id; + resp.qp_handle = uobj->uobject.id; spin_lock_irq(&file->ucontext->lock); - list_add_tail(&uobj->list, &file->ucontext->qp_list); + list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); spin_unlock_irq(&file->ucontext->lock); if (copy_to_user((void __user *) (unsigned long) cmd.response, @@ -830,7 +863,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, err_list: spin_lock_irq(&file->ucontext->lock); - list_del(&uobj->list); + list_del(&uobj->uobject.list); spin_unlock_irq(&file->ucontext->lock); err_destroy: @@ -930,21 +963,25 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) { - struct ib_uverbs_destroy_qp cmd; - struct ib_qp *qp; - struct ib_uobject *uobj; - int ret = -EINVAL; + struct ib_uverbs_destroy_qp cmd; + struct ib_uverbs_destroy_qp_resp resp; + struct ib_qp *qp; + struct ib_uevent_object *uobj; + struct ib_uverbs_event *evt, *tmp; + int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; + memset(&resp, 0, sizeof resp); + down(&ib_uverbs_idr_mutex); qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); if (!qp || qp->uobject->context != file->ucontext) goto out; - uobj = qp->uobject; + uobj = container_of(qp->uobject, struct ib_uevent_object, uobject); ret = ib_destroy_qp(qp); if (ret) @@ -953,11 +990,24 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); spin_lock_irq(&file->ucontext->lock); - list_del(&uobj->list); + list_del(&uobj->uobject.list); spin_unlock_irq(&file->ucontext->lock); + spin_lock_irq(&file->async_file.lock); + list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&file->async_file.lock); + + resp.events_reported = uobj->events_reported; + kfree(uobj); + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + out: up(&ib_uverbs_idr_mutex); @@ -1015,7 +1065,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, struct ib_uverbs_create_srq cmd; struct ib_uverbs_create_srq_resp resp; struct ib_udata udata; - struct ib_uobject *uobj; + struct ib_uevent_object *uobj; struct ib_pd *pd; struct ib_srq *srq; struct ib_srq_init_attr attr; @@ -1050,8 +1100,10 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, attr.attr.max_sge = cmd.max_sge; attr.attr.srq_limit = cmd.srq_limit; - uobj->user_handle = cmd.user_handle; - uobj->context = file->ucontext; + uobj->uobject.user_handle = cmd.user_handle; + uobj->uobject.context = file->ucontext; + uobj->events_reported = 0; + INIT_LIST_HEAD(&uobj->event_list); srq = pd->device->create_srq(pd, &attr, &udata); if (IS_ERR(srq)) { @@ -1061,7 +1113,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, srq->device = pd->device; srq->pd = pd; - srq->uobject = uobj; + srq->uobject = &uobj->uobject; srq->event_handler = attr.event_handler; srq->srq_context = attr.srq_context; atomic_inc(&pd->usecnt); @@ -1075,17 +1127,17 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, goto err_destroy; } - ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->id); + ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->uobject.id); if (ret == -EAGAIN) goto retry; if (ret) goto err_destroy; - resp.srq_handle = uobj->id; + resp.srq_handle = uobj->uobject.id; spin_lock_irq(&file->ucontext->lock); - list_add_tail(&uobj->list, &file->ucontext->srq_list); + list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); spin_unlock_irq(&file->ucontext->lock); if (copy_to_user((void __user *) (unsigned long) cmd.response, @@ -1100,7 +1152,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, err_list: spin_lock_irq(&file->ucontext->lock); - list_del(&uobj->list); + list_del(&uobj->uobject.list); spin_unlock_irq(&file->ucontext->lock); err_destroy: @@ -1149,21 +1201,25 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, const char __user *buf, int in_len, int out_len) { - struct ib_uverbs_destroy_srq cmd; - struct ib_srq *srq; - struct ib_uobject *uobj; - int ret = -EINVAL; + struct ib_uverbs_destroy_srq cmd; + struct ib_uverbs_destroy_srq_resp resp; + struct ib_srq *srq; + struct ib_uevent_object *uobj; + struct ib_uverbs_event *evt, *tmp; + int ret = -EINVAL; if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; down(&ib_uverbs_idr_mutex); + memset(&resp, 0, sizeof resp); + srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); if (!srq || srq->uobject->context != file->ucontext) goto out; - uobj = srq->uobject; + uobj = container_of(srq->uobject, struct ib_uevent_object, uobject); ret = ib_destroy_srq(srq); if (ret) @@ -1172,11 +1228,24 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle); spin_lock_irq(&file->ucontext->lock); - list_del(&uobj->list); + list_del(&uobj->uobject.list); spin_unlock_irq(&file->ucontext->lock); + spin_lock_irq(&file->async_file.lock); + list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&file->async_file.lock); + + resp.events_reported = uobj->events_reported; + kfree(uobj); + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + out: up(&ib_uverbs_idr_mutex); diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 09caf5b1ef361..ce5bdb7af3063 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -120,7 +120,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) idr_remove(&ib_uverbs_qp_idr, uobj->id); ib_destroy_qp(qp); list_del(&uobj->list); - kfree(uobj); + kfree(container_of(uobj, struct ib_uevent_object, uobject)); } list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { @@ -128,7 +128,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) idr_remove(&ib_uverbs_cq_idr, uobj->id); ib_destroy_cq(cq); list_del(&uobj->list); - kfree(uobj); + kfree(container_of(uobj, struct ib_ucq_object, uobject)); } list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { @@ -136,7 +136,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) idr_remove(&ib_uverbs_srq_idr, uobj->id); ib_destroy_srq(srq); list_del(&uobj->list); - kfree(uobj); + kfree(container_of(uobj, struct ib_uevent_object, uobject)); } /* XXX Free MWs */ @@ -182,7 +182,7 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { struct ib_uverbs_event_file *file = filp->private_data; - void *event; + struct ib_uverbs_event *event; int eventsz; int ret = 0; @@ -207,21 +207,23 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, return -ENODEV; } - if (file->is_async) { - event = list_entry(file->event_list.next, - struct ib_uverbs_async_event, list); + event = list_entry(file->event_list.next, struct ib_uverbs_event, list); + + if (file->is_async) eventsz = sizeof (struct ib_uverbs_async_event_desc); - } else { - event = list_entry(file->event_list.next, - struct ib_uverbs_comp_event, list); + else eventsz = sizeof (struct ib_uverbs_comp_event_desc); - } if (eventsz > count) { ret = -EINVAL; event = NULL; - } else + } else { list_del(file->event_list.next); + if (event->counter) { + ++(*event->counter); + list_del(&event->obj_list); + } + } spin_unlock_irq(&file->lock); @@ -257,16 +259,13 @@ static unsigned int ib_uverbs_event_poll(struct file *filp, static void ib_uverbs_event_release(struct ib_uverbs_event_file *file) { - struct list_head *entry, *tmp; + struct ib_uverbs_event *entry, *tmp; spin_lock_irq(&file->lock); if (file->fd != -1) { file->fd = -1; - list_for_each_safe(entry, tmp, &file->event_list) - if (file->is_async) - kfree(list_entry(entry, struct ib_uverbs_async_event, list)); - else - kfree(list_entry(entry, struct ib_uverbs_comp_event, list)); + list_for_each_entry_safe(entry, tmp, &file->event_list, list) + kfree(entry); } spin_unlock_irq(&file->lock); } @@ -304,18 +303,23 @@ static struct file_operations uverbs_event_fops = { void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) { - struct ib_uverbs_file *file = cq_context; - struct ib_uverbs_comp_event *entry; - unsigned long flags; + struct ib_uverbs_file *file = cq_context; + struct ib_ucq_object *uobj; + struct ib_uverbs_event *entry; + unsigned long flags; entry = kmalloc(sizeof *entry, GFP_ATOMIC); if (!entry) return; - entry->desc.cq_handle = cq->uobject->user_handle; + uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); + + entry->desc.comp.cq_handle = cq->uobject->user_handle; + entry->counter = &uobj->comp_events_reported; spin_lock_irqsave(&file->comp_file[0].lock, flags); list_add_tail(&entry->list, &file->comp_file[0].event_list); + list_add_tail(&entry->obj_list, &uobj->comp_list); spin_unlock_irqrestore(&file->comp_file[0].lock, flags); wake_up_interruptible(&file->comp_file[0].poll_wait); @@ -323,20 +327,25 @@ void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) } static void ib_uverbs_async_handler(struct ib_uverbs_file *file, - __u64 element, __u64 event) + __u64 element, __u64 event, + struct list_head *obj_list, + u32 *counter) { - struct ib_uverbs_async_event *entry; + struct ib_uverbs_event *entry; unsigned long flags; entry = kmalloc(sizeof *entry, GFP_ATOMIC); if (!entry) return; - entry->desc.element = element; - entry->desc.event_type = event; + entry->desc.async.element = element; + entry->desc.async.event_type = event; + entry->counter = counter; spin_lock_irqsave(&file->async_file.lock, flags); list_add_tail(&entry->list, &file->async_file.event_list); + if (obj_list) + list_add_tail(&entry->obj_list, obj_list); spin_unlock_irqrestore(&file->async_file.lock, flags); wake_up_interruptible(&file->async_file.poll_wait); @@ -345,23 +354,39 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file, void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) { - ib_uverbs_async_handler(context_ptr, - event->element.cq->uobject->user_handle, - event->event); + struct ib_ucq_object *uobj; + + uobj = container_of(event->element.cq->uobject, + struct ib_ucq_object, uobject); + + ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, + event->event, &uobj->async_list, + &uobj->async_events_reported); + } void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr) { - ib_uverbs_async_handler(context_ptr, - event->element.qp->uobject->user_handle, - event->event); + struct ib_uevent_object *uobj; + + uobj = container_of(event->element.qp->uobject, + struct ib_uevent_object, uobject); + + ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, + event->event, &uobj->event_list, + &uobj->events_reported); } void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr) { - ib_uverbs_async_handler(context_ptr, - event->element.srq->uobject->user_handle, - event->event); + struct ib_uevent_object *uobj; + + uobj = container_of(event->element.srq->uobject, + struct ib_uevent_object, uobject); + + ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, + event->event, &uobj->event_list, + &uobj->events_reported); } static void ib_uverbs_event_handler(struct ib_event_handler *handler, @@ -370,7 +395,8 @@ static void ib_uverbs_event_handler(struct ib_event_handler *handler, struct ib_uverbs_file *file = container_of(handler, struct ib_uverbs_file, event_handler); - ib_uverbs_async_handler(file, event->element.port_num, event->event); + ib_uverbs_async_handler(file, event->element.port_num, event->event, + NULL, NULL); } static int ib_uverbs_event_init(struct ib_uverbs_event_file *file, diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h index 7ebb01c8f9963..fd85725391a4e 100644 --- a/include/rdma/ib_user_verbs.h +++ b/include/rdma/ib_user_verbs.h @@ -42,7 +42,7 @@ * Increment this value if any changes that break userspace ABI * compatibility are made. */ -#define IB_USER_VERBS_ABI_VERSION 1 +#define IB_USER_VERBS_ABI_VERSION 2 enum { IB_USER_VERBS_CMD_QUERY_PARAMS, @@ -292,7 +292,14 @@ struct ib_uverbs_create_cq_resp { }; struct ib_uverbs_destroy_cq { + __u64 response; __u32 cq_handle; + __u32 reserved; +}; + +struct ib_uverbs_destroy_cq_resp { + __u32 comp_events_reported; + __u32 async_events_reported; }; struct ib_uverbs_create_qp { @@ -372,7 +379,13 @@ struct ib_uverbs_modify_qp_resp { }; struct ib_uverbs_destroy_qp { + __u64 response; __u32 qp_handle; + __u32 reserved; +}; + +struct ib_uverbs_destroy_qp_resp { + __u32 events_reported; }; struct ib_uverbs_attach_mcast { @@ -416,7 +429,13 @@ struct ib_uverbs_modify_srq { }; struct ib_uverbs_destroy_srq { + __u64 response; __u32 srq_handle; + __u32 reserved; +}; + +struct ib_uverbs_destroy_srq_resp { + __u32 events_reported; }; #endif /* IB_USER_VERBS_H */ -- GitLab From d7e0fb985cb033e605c3167ff183b5e98b7f7644 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 19:58:18 -0300 Subject: [PATCH 298/563] [CCID3] Initialize ccid3hctx_t_ipi to 250ms To match more closely what is described in RFC 3448. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> Signed-off-by: Ian McDonald <iam4@cs.waikato.ac.nz> --- net/dccp/ccids/ccid3.c | 2 +- net/dccp/ccids/ccid3.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index ea30012dd1954..4467a74e6f40a 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -328,7 +328,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, hctx->ccid3hctx_last_win_count = 0; hctx->ccid3hctx_t_last_win_count = now; ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK); - hctx->ccid3hctx_t_ipi = TFRC_INITIAL_TIMEOUT; + hctx->ccid3hctx_t_ipi = TFRC_INITIAL_IPI; /* Set nominal send time for initial packet */ hctx->ccid3hctx_t_nom = now; diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index d16f00d784f39..eb248778eea37 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -48,6 +48,8 @@ /* Two seconds as per CCID3 spec */ #define TFRC_INITIAL_TIMEOUT (2 * USEC_PER_SEC) +#define TFRC_INITIAL_IPI (USEC_PER_SEC / 4) + /* In usecs - half the scheduling granularity as per RFC3448 4.6 */ #define TFRC_OPSYS_HALF_TIME_GRAN (USEC_PER_SEC / (2 * HZ)) -- GitLab From dc19336c76d213fd9ae7b6a352e837f509418012 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 19:59:26 -0300 Subject: [PATCH 299/563] [DCCP] Only call the HC _exit() routines in dccp_v4_destroy_sock Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- net/dccp/ipv4.c | 4 ---- net/dccp/output.c | 3 --- 2 files changed, 7 deletions(-) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index fee9a8c3777b3..2afaa464e7f09 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -641,16 +641,12 @@ int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code) skb = dccp_make_reset(sk, sk->sk_dst_cache, code); if (skb != NULL) { - const struct dccp_sock *dp = dccp_sk(sk); const struct inet_sock *inet = inet_sk(sk); err = ip_build_and_send_pkt(skb, sk, inet->saddr, inet->daddr, NULL); if (err == NET_XMIT_CN) err = 0; - - ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); - ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); } return err; diff --git a/net/dccp/output.c b/net/dccp/output.c index 28de157a43261..ea6d0e91e5117 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -522,7 +522,4 @@ void dccp_send_close(struct sock *sk, const int active) dccp_transmit_skb(sk, skb_clone(skb, prio)); } else dccp_transmit_skb(sk, skb); - - ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); - ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); } -- GitLab From 59d203f9e989c81defc2cb1c559d678e16dbe684 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo <acme@mandriva.com> Date: Fri, 9 Sep 2005 20:01:25 -0300 Subject: [PATCH 300/563] [CCID3] Cleanup ccid3 debug calls Also use some BUG_ON where appropriate and use LIMIT_NETDEBUG for the unlikely cases where we, at this stage, want to know about, that in my tests hasn't appeared in the radar. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> --- net/dccp/ccids/ccid3.c | 164 +++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 97 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 4467a74e6f40a..e05f4f955eeee 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -78,13 +78,11 @@ static struct dccp_li_hist *ccid3_li_hist; static int ccid3_init(struct sock *sk) { - ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); return 0; } static void ccid3_exit(struct sock *sk) { - ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); } /* TFRC sender states */ @@ -287,14 +285,14 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, long delay; int rc = -ENOTCONN; - /* Check if pure ACK or Terminating*/ + BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM); + /* Check if pure ACK or Terminating*/ /* * XXX: We only call this function for DATA and DATAACK, on, these * packets can have zero length, but why the comment about "pure ACK"? */ - if (hctx == NULL || len == 0 || - hctx->ccid3hctx_state == TFRC_SSTATE_TERM) + if (unlikely(len == 0)) goto out; /* See if last packet allocated was not sent */ @@ -304,10 +302,10 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, SLAB_ATOMIC); rc = -ENOBUFS; - if (new_packet == NULL) { - ccid3_pr_debug("%s, sk=%p, not enough mem to add " - "to history, send refused\n", - dccp_role(sk), sk); + if (unlikely(new_packet == NULL)) { + LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, not enough " + "mem to add to history, send refused\n", + __FUNCTION__, dccp_role(sk), sk); goto out; } @@ -318,9 +316,6 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, switch (hctx->ccid3hctx_state) { case TFRC_SSTATE_NO_SENT: - ccid3_pr_debug("%s, sk=%p, first packet(%llu)\n", - dccp_role(sk), sk, dp->dccps_gss); - hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer; hctx->ccid3hctx_no_feedback_timer.data = (unsigned long)sk; sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, @@ -341,7 +336,6 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, case TFRC_SSTATE_FBACK: delay = (timeval_delta(&now, &hctx->ccid3hctx_t_nom) - hctx->ccid3hctx_delta); - ccid3_pr_debug("send_packet delay=%ld\n", delay); delay /= -1000; /* divide by -1000 is to convert to ms and get sign right */ rc = delay > 0 ? delay : 0; @@ -371,13 +365,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len) struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct timeval now; - BUG_ON(hctx == NULL); - - if (hctx->ccid3hctx_state == TFRC_SSTATE_TERM) { - ccid3_pr_debug("%s, sk=%p, while state is TFRC_SSTATE_TERM!\n", - dccp_role(sk), sk); - return; - } + BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM); dccp_timestamp(sk, &now); @@ -387,14 +375,14 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len) struct dccp_tx_hist_entry *packet; packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist); - if (packet == NULL) { - printk(KERN_CRIT "%s: packet doesn't exists in " - "history!\n", __FUNCTION__); + if (unlikely(packet == NULL)) { + LIMIT_NETDEBUG(KERN_WARNING "%s: packet doesn't " + "exists in history!\n", __FUNCTION__); return; } - if (packet->dccphtx_sent) { - printk(KERN_CRIT "%s: no unsent packet in history!\n", - __FUNCTION__); + if (unlikely(packet->dccphtx_sent)) { + LIMIT_NETDEBUG(KERN_WARNING "%s: no unsent packet in " + "history!\n", __FUNCTION__); return; } packet->dccphtx_tstamp = now; @@ -465,14 +453,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) u32 x_recv; u32 r_sample; - if (hctx == NULL) - return; - - if (hctx->ccid3hctx_state == TFRC_SSTATE_TERM) { - ccid3_pr_debug("%s, sk=%p, received a packet when " - "terminating!\n", dccp_role(sk), sk); - return; - } + BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM); /* we are only interested in ACKs */ if (!(DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK || @@ -496,12 +477,12 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) /* get t_recvdata from history */ packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist, DCCP_SKB_CB(skb)->dccpd_ack_seq); - if (packet == NULL) { - ccid3_pr_debug("%s, sk=%p, seqno %llu(%s) does't " - "exist in history!\n", - dccp_role(sk), sk, - DCCP_SKB_CB(skb)->dccpd_ack_seq, - dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type)); + if (unlikely(packet == NULL)) { + LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, seqno " + "%llu(%s) does't exist in history!\n", + __FUNCTION__, dccp_role(sk), sk, + (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq, + dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type)); return; } @@ -509,8 +490,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) dccp_timestamp(sk, &now); r_sample = timeval_delta(&now, &packet->dccphtx_tstamp); if (unlikely(r_sample <= t_elapsed)) - LIMIT_NETDEBUG(KERN_WARNING - "%s: r_sample=%uus, t_elapsed=%uus\n", + LIMIT_NETDEBUG(KERN_WARNING "%s: r_sample=%uus, " + "t_elapsed=%uus\n", __FUNCTION__, r_sample, t_elapsed); else r_sample -= t_elapsed; @@ -606,10 +587,11 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) static void ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb) { - struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); + const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); - if (hctx == NULL || !(sk->sk_state == DCCP_OPEN || - sk->sk_state == DCCP_PARTOPEN)) + BUG_ON(hctx == NULL); + + if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)) return; DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count; @@ -624,8 +606,7 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct ccid3_options_received *opt_recv; - if (hctx == NULL) - return 0; + BUG_ON(hctx == NULL); opt_recv = &hctx->ccid3hctx_options_received; @@ -639,10 +620,10 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, switch (option) { case TFRC_OPT_LOSS_EVENT_RATE: - if (len != 4) { - ccid3_pr_debug("%s, sk=%p, invalid len for " - "TFRC_OPT_LOSS_EVENT_RATE\n", - dccp_role(sk), sk); + if (unlikely(len != 4)) { + LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, invalid " + "len for TFRC_OPT_LOSS_EVENT_RATE\n", + __FUNCTION__, dccp_role(sk), sk); rc = -EINVAL; } else { opt_recv->ccid3or_loss_event_rate = ntohl(*(u32 *)value); @@ -660,10 +641,10 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, opt_recv->ccid3or_loss_intervals_len); break; case TFRC_OPT_RECEIVE_RATE: - if (len != 4) { - ccid3_pr_debug("%s, sk=%p, invalid len for " - "TFRC_OPT_RECEIVE_RATE\n", - dccp_role(sk), sk); + if (unlikely(len != 4)) { + LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, invalid " + "len for TFRC_OPT_RECEIVE_RATE\n", + __FUNCTION__, dccp_role(sk), sk); rc = -EINVAL; } else { opt_recv->ccid3or_receive_rate = ntohl(*(u32 *)value); @@ -682,8 +663,6 @@ static int ccid3_hc_tx_init(struct sock *sk) struct dccp_sock *dp = dccp_sk(sk); struct ccid3_hc_tx_sock *hctx; - ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); - dp->dccps_hc_tx_ccid_private = kmalloc(sizeof(*hctx), gfp_any()); if (dp->dccps_hc_tx_ccid_private == NULL) return -ENOMEM; @@ -712,7 +691,6 @@ static void ccid3_hc_tx_exit(struct sock *sk) struct dccp_sock *dp = dccp_sk(sk); struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); - ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); BUG_ON(hctx == NULL); ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM); @@ -792,10 +770,10 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) } packet = dccp_rx_hist_find_data_packet(&hcrx->ccid3hcrx_hist); - if (packet == NULL) { - printk(KERN_CRIT "%s: %s, sk=%p, no data packet in history!\n", - __FUNCTION__, dccp_role(sk), sk); - dump_stack(); + if (unlikely(packet == NULL)) { + LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, no data packet " + "in history!\n", + __FUNCTION__, dccp_role(sk), sk); return; } @@ -817,11 +795,12 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) { - struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); + const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); u32 x_recv, pinv; - if (hcrx == NULL || !(sk->sk_state == DCCP_OPEN || - sk->sk_state == DCCP_PARTOPEN)) + BUG_ON(hcrx == NULL); + + if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)) return; DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_last_counter; @@ -878,17 +857,17 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk) } } - if (step == 0) { - printk(KERN_CRIT "%s: %s, sk=%p, packet history contains no " - "data packets!\n", - __FUNCTION__, dccp_role(sk), sk); + if (unlikely(step == 0)) { + LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, packet history " + "contains no data packets!\n", + __FUNCTION__, dccp_role(sk), sk); return ~0; } - if (interval == 0) { - ccid3_pr_debug("%s, sk=%p, Could not find a win_count " - "interval > 0. Defaulting to 1\n", - dccp_role(sk), sk); + if (unlikely(interval == 0)) { + LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, Could not find a " + "win_count interval > 0. Defaulting to 1\n", + __FUNCTION__, dccp_role(sk), sk); interval = 1; } found: @@ -931,8 +910,9 @@ static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss) if (li_tail == NULL) return; li_tail->dccplih_interval = ccid3_hc_rx_calc_first_li(sk); - } - /* FIXME: find end of interval */ + } else + LIMIT_NETDEBUG(KERN_WARNING "%s: FIXME: find end of " + "interval\n", __FUNCTION__); } static void ccid3_hc_rx_detect_loss(struct sock *sk) @@ -956,10 +936,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) u32 p_prev, r_sample, t_elapsed; int ins; - if (hcrx == NULL) - return; - - BUG_ON(!(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA || + BUG_ON(hcrx == NULL || + !(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA || hcrx->ccid3hcrx_state == TFRC_RSTATE_DATA)); opt_recv = &dccp_sk(sk)->dccps_options_received; @@ -978,8 +956,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) t_elapsed = opt_recv->dccpor_elapsed_time * 10; if (unlikely(r_sample <= t_elapsed)) - LIMIT_NETDEBUG(KERN_WARNING - "%s: r_sample=%uus, t_elapsed=%uus\n", + LIMIT_NETDEBUG(KERN_WARNING "%s: r_sample=%uus, " + "t_elapsed=%uus\n", __FUNCTION__, r_sample, t_elapsed); else r_sample -= t_elapsed; @@ -997,19 +975,16 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) break; case DCCP_PKT_DATA: break; - default: - ccid3_pr_debug("%s, sk=%p, not DATA/DATAACK/ACK packet(%s)\n", - dccp_role(sk), sk, - dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type)); + default: /* We're not interested in other packet types, move along */ return; } packet = dccp_rx_hist_entry_new(ccid3_rx_hist, sk, opt_recv->dccpor_ndp, skb, SLAB_ATOMIC); - if (packet == NULL) { - ccid3_pr_debug("%s, sk=%p, Not enough mem to add rx packet " - "to history (consider it lost)!", - dccp_role(sk), sk); + if (unlikely(packet == NULL)) { + LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, Not enough mem to " + "add rx packet to history, consider it lost!\n", + __FUNCTION__, dccp_role(sk), sk); return; } @@ -1102,10 +1077,7 @@ static void ccid3_hc_rx_exit(struct sock *sk) struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); struct dccp_sock *dp = dccp_sk(sk); - ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); - - if (hcrx == NULL) - return; + BUG_ON(hcrx == NULL); ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM); @@ -1123,8 +1095,7 @@ static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) { const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); - if (hcrx == NULL) - return; + BUG_ON(hcrx == NULL); info->tcpi_ca_state = hcrx->ccid3hcrx_state; info->tcpi_options |= TCPI_OPT_TIMESTAMPS; @@ -1135,8 +1106,7 @@ static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) { const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); - if (hctx == NULL) - return; + BUG_ON(hctx == NULL); info->tcpi_rto = hctx->ccid3hctx_t_rto; info->tcpi_rtt = hctx->ccid3hctx_rtt; -- GitLab From 3ec67ac1a399d576d48b0736096bcce7721fe3cf Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:40 -0700 Subject: [PATCH 301/563] [PATCH] md: fix minor error in raid10 read-balancing calculation. 'this_sector' is a virtual (array) address while 'head_position' is a physical (device) address, so substraction doesn't make any sense. devs[slot].addr should be used instead of this_sector. However, this patch doesn't make much practical different to the read balancing due to the effects of later code. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/raid10.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 62ebb1bc72be2..7239079203ec1 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -538,7 +538,8 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio) } - current_distance = abs(this_sector - conf->mirrors[disk].head_position); + current_distance = abs(r10_bio->devs[slot].addr - + conf->mirrors[disk].head_position); /* Find the disk whose head is closest */ -- GitLab From e5dcdd80a60627371f40797426273048630dc8ca Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:41 -0700 Subject: [PATCH 302/563] [PATCH] md: fail IO request to md that require a barrier. md does not yet support BIO_RW_BARRIER, so be honest about it and fail (-EOPNOTSUPP) any such requests. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/linear.c | 5 +++++ drivers/md/multipath.c | 5 +++++ drivers/md/raid0.c | 5 +++++ drivers/md/raid1.c | 4 ++++ drivers/md/raid10.c | 5 +++++ drivers/md/raid5.c | 5 +++++ drivers/md/raid6main.c | 5 +++++ 7 files changed, 34 insertions(+) diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 8d740013d74d5..4991ba543368a 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -238,6 +238,11 @@ static int linear_make_request (request_queue_t *q, struct bio *bio) dev_info_t *tmp_dev; sector_t block; + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } + if (bio_data_dir(bio)==WRITE) { disk_stat_inc(mddev->gendisk, writes); disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bio)); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 2d2ca7fa02652..286342375fb7f 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -169,6 +169,11 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio) struct multipath_bh * mp_bh; struct multipath_info *multipath; + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } + mp_bh = mempool_alloc(conf->pool, GFP_NOIO); mp_bh->master_bio = bio; diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 2120710172c54..f6757259ce7fe 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -404,6 +404,11 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio) unsigned long chunk; sector_t block, rsect; + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } + if (bio_data_dir(bio)==WRITE) { disk_stat_inc(mddev->gendisk, writes); disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bio)); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 51d9645ed09c5..ace41c571aeb3 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -555,6 +555,10 @@ static int make_request(request_queue_t *q, struct bio * bio) unsigned long flags; struct bio_list bl; + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } /* * Register the new request and wait if the reconstruction diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 7239079203ec1..5e0b333793d5b 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -669,6 +669,11 @@ static int make_request(request_queue_t *q, struct bio * bio) int i; int chunk_sects = conf->chunk_mask + 1; + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } + /* If this request crosses a chunk boundary, we need to * split it. This will only happen for 1 PAGE (or less) requests. */ diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 43f231a467d5c..ed859e08d600f 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1411,6 +1411,11 @@ static int make_request (request_queue_t *q, struct bio * bi) sector_t logical_sector, last_sector; struct stripe_head *sh; + if (unlikely(bio_barrier(bi))) { + bio_endio(bi, bi->bi_size, -EOPNOTSUPP); + return 0; + } + md_write_start(mddev, bi); if (bio_data_dir(bi)==WRITE) { diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 495dee1d1e833..09cb7272c09f9 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -1570,6 +1570,11 @@ static int make_request (request_queue_t *q, struct bio * bi) sector_t logical_sector, last_sector; struct stripe_head *sh; + if (unlikely(bio_barrier(bi))) { + bio_endio(bi, bi->bi_size, -EOPNOTSUPP); + return 0; + } + md_write_start(mddev, bi); if (bio_data_dir(bi)==WRITE) { -- GitLab From 844e8d904a7c1446e3f040683b4a0645c3eb168f Mon Sep 17 00:00:00 2001 From: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Date: Fri, 9 Sep 2005 16:23:42 -0700 Subject: [PATCH 303/563] [PATCH] dm: fix rh_dec()/rh_inc() race in dm-raid1.c Fix another bug in dm-raid1.c that the dirty region may stay in or be moved to clean list and freed while in use. It happens as follows: CPU0 CPU1 ------------------------------------------------------------------------------ rh_dec() if (atomic_dec_and_test(pending)) <the region is still marked dirty> rh_inc() if the region is clean mark the region dirty and remove from clean list mark the region clean and move to clean list atomic_inc(pending) At this stage, the region is in clean list and will be mistakenly reclaimed by rh_update_states() later. Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/dm-raid1.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index b08df8b9b2cad..8632825137538 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -375,16 +375,18 @@ static void rh_inc(struct region_hash *rh, region_t region) read_lock(&rh->hash_lock); reg = __rh_find(rh, region); + + atomic_inc(®->pending); + + spin_lock_irq(&rh->region_lock); if (reg->state == RH_CLEAN) { rh->log->type->mark_region(rh->log, reg->key); - spin_lock_irq(&rh->region_lock); reg->state = RH_DIRTY; list_del_init(®->list); /* take off the clean list */ - spin_unlock_irq(&rh->region_lock); } + spin_unlock_irq(&rh->region_lock); - atomic_inc(®->pending); read_unlock(&rh->hash_lock); } @@ -408,6 +410,10 @@ static void rh_dec(struct region_hash *rh, region_t region) if (atomic_dec_and_test(®->pending)) { spin_lock_irqsave(&rh->region_lock, flags); + if (atomic_read(®->pending)) { /* check race */ + spin_unlock_irqrestore(&rh->region_lock, flags); + return; + } if (reg->state == RH_RECOVERING) { list_add_tail(®->list, &rh->quiesced_regions); } else { -- GitLab From 1923b99a0f4748aa6be0b9b9523ce224a3449b17 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:43 -0700 Subject: [PATCH 304/563] [PATCH] md: don't allow new md/bitmap file to be set if one already exists ... otherwise we loose a reference and can never free the file. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 373ab92e367b8..63c566165189a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2430,7 +2430,7 @@ static int set_bitmap_file(mddev_t *mddev, int fd) { int err; - if (mddev->pers) + if (mddev->pers || mddev->bitmap_file) return -EBUSY; mddev->bitmap_file = fget(fd); -- GitLab From 6a07997fc34ac15a1c5dc650285d79b7604a2276 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:44 -0700 Subject: [PATCH 305/563] [PATCH] md: improve handling of bitmap initialisation. When we find a 'stale' bitmap, possibly because it is new, we should just assume every bit needs to be set, but rather base the setting of bits on the current state of the array (degraded and recovery_cp). Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/bitmap.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 41df4cda66e2f..2925219f08819 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -520,6 +520,8 @@ static int bitmap_read_sb(struct bitmap *bitmap) bitmap->daemon_sleep = daemon_sleep; bitmap->flags |= sb->state; bitmap->events_cleared = le64_to_cpu(sb->events_cleared); + if (sb->state & BITMAP_STALE) + bitmap->events_cleared = bitmap->mddev->events; err = 0; out: kunmap(bitmap->sb_page); @@ -818,7 +820,7 @@ int bitmap_unplug(struct bitmap *bitmap) return 0; } -static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset); +static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed); /* * bitmap_init_from_disk -- called at bitmap_create time to initialize * the in-memory bitmap from the on-disk bitmap -- also, sets up the * memory mapping of the bitmap file @@ -826,8 +828,11 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset); * if there's no bitmap file, or if the bitmap file had been * previously kicked from the array, we mark all the bits as * 1's in order to cause a full resync. + * + * We ignore all bits for sectors that end earlier than 'start'. + * This is used when reading an out-of-date bitmap... */ -static int bitmap_init_from_disk(struct bitmap *bitmap) +static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) { unsigned long i, chunks, index, oldindex, bit; struct page *page = NULL, *oldpage = NULL; @@ -914,7 +919,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) * whole page and write it out */ memset(page_address(page) + offset, 0xff, - PAGE_SIZE - offset); + PAGE_SIZE - offset); ret = write_page(bitmap, page, 1); if (ret) { kunmap(page); @@ -928,8 +933,11 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) } if (test_bit(bit, page_address(page))) { /* if the disk bit is set, set the memory bit */ - bitmap_set_memory_bits(bitmap, i << CHUNK_BLOCK_SHIFT(bitmap)); + bitmap_set_memory_bits(bitmap, i << CHUNK_BLOCK_SHIFT(bitmap), + ((i+1) << (CHUNK_BLOCK_SHIFT(bitmap)) >= start) + ); bit_cnt++; + set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); } } @@ -1424,7 +1432,7 @@ void bitmap_close_sync(struct bitmap *bitmap) } } -static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset) +static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed) { /* For each chunk covered by any of these sectors, set the * counter to 1 and set resync_needed. They should all @@ -1441,7 +1449,7 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset) } if (! *bmc) { struct page *page; - *bmc = 1 | NEEDED_MASK; + *bmc = 1 | (needed?NEEDED_MASK:0); bitmap_count_page(bitmap, offset, 1); page = filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)); set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); @@ -1517,6 +1525,7 @@ int bitmap_create(mddev_t *mddev) unsigned long pages; struct file *file = mddev->bitmap_file; int err; + sector_t start; BUG_ON(sizeof(bitmap_super_t) != 256); @@ -1581,7 +1590,12 @@ int bitmap_create(mddev_t *mddev) /* now that we have some pages available, initialize the in-memory * bitmap from the on-disk bitmap */ - err = bitmap_init_from_disk(bitmap); + start = 0; + if (mddev->degraded == 0 + || bitmap->events_cleared == mddev->events) + /* no need to keep dirty bits to optimise a re-add of a missing device */ + start = mddev->recovery_cp; + err = bitmap_init_from_disk(bitmap, start); if (err) return err; -- GitLab From 36fa30636fb84b209210299684e1be66d9e58217 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:45 -0700 Subject: [PATCH 306/563] [PATCH] md: all hot-add and hot-remove of md intent logging bitmaps Both file-bitmaps and superblock bitmaps are supported. If you add a bitmap file on the array device, you lose. This introduces a 'default_bitmap_offset' field in mddev, as the ioctl used for adding a superblock bitmap doesn't have room for giving an offset. Later, this value will be setable via sysfs. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 104 +++++++++++++++++++++++++++++++------- drivers/md/raid1.c | 30 +++++++++++ include/linux/raid/md_k.h | 10 ++++ 3 files changed, 127 insertions(+), 17 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 63c566165189a..ae654466dc239 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -623,6 +623,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->size = sb->size; mddev->events = md_event(sb); mddev->bitmap_offset = 0; + mddev->default_bitmap_offset = MD_SB_BYTES >> 9; if (sb->state & (1<<MD_SB_CLEAN)) mddev->recovery_cp = MaxSector; @@ -648,7 +649,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) printk(KERN_WARNING "md: bitmaps only support for raid1\n"); return -EINVAL; } - mddev->bitmap_offset = (MD_SB_BYTES >> 9); + mddev->bitmap_offset = mddev->default_bitmap_offset; } } else if (mddev->pers == NULL) { @@ -939,6 +940,9 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->size = le64_to_cpu(sb->size)/2; mddev->events = le64_to_cpu(sb->events); mddev->bitmap_offset = 0; + mddev->default_bitmap_offset = 0; + if (mddev->minor_version == 0) + mddev->default_bitmap_offset = -(64*1024)/512; mddev->recovery_cp = le64_to_cpu(sb->resync_offset); memcpy(mddev->uuid, sb->set_uuid, 16); @@ -2073,6 +2077,8 @@ static int get_array_info(mddev_t * mddev, void __user * arg) info.state = 0; if (mddev->in_sync) info.state = (1<<MD_SB_CLEAN); + if (mddev->bitmap && mddev->bitmap_offset) + info.state = (1<<MD_SB_BITMAP_PRESENT); info.active_disks = active; info.working_disks = working; info.failed_disks = failed; @@ -2430,25 +2436,51 @@ static int set_bitmap_file(mddev_t *mddev, int fd) { int err; - if (mddev->pers || mddev->bitmap_file) - return -EBUSY; + if (mddev->pers) { + if (!mddev->pers->quiesce) + return -EBUSY; + if (mddev->recovery || mddev->sync_thread) + return -EBUSY; + /* we should be able to change the bitmap.. */ + } - mddev->bitmap_file = fget(fd); - if (mddev->bitmap_file == NULL) { - printk(KERN_ERR "%s: error: failed to get bitmap file\n", - mdname(mddev)); - return -EBADF; - } + if (fd >= 0) { + if (mddev->bitmap) + return -EEXIST; /* cannot add when bitmap is present */ + mddev->bitmap_file = fget(fd); - err = deny_bitmap_write_access(mddev->bitmap_file); - if (err) { - printk(KERN_ERR "%s: error: bitmap file is already in use\n", - mdname(mddev)); - fput(mddev->bitmap_file); - mddev->bitmap_file = NULL; - } else + if (mddev->bitmap_file == NULL) { + printk(KERN_ERR "%s: error: failed to get bitmap file\n", + mdname(mddev)); + return -EBADF; + } + + err = deny_bitmap_write_access(mddev->bitmap_file); + if (err) { + printk(KERN_ERR "%s: error: bitmap file is already in use\n", + mdname(mddev)); + fput(mddev->bitmap_file); + mddev->bitmap_file = NULL; + return err; + } mddev->bitmap_offset = 0; /* file overrides offset */ + } else if (mddev->bitmap == NULL) + return -ENOENT; /* cannot remove what isn't there */ + err = 0; + if (mddev->pers) { + mddev->pers->quiesce(mddev, 1); + if (fd >= 0) + err = bitmap_create(mddev); + if (fd < 0 || err) + bitmap_destroy(mddev); + mddev->pers->quiesce(mddev, 0); + } else if (fd < 0) { + if (mddev->bitmap_file) + fput(mddev->bitmap_file); + mddev->bitmap_file = NULL; + } + return err; } @@ -2528,6 +2560,11 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) { int rv = 0; int cnt = 0; + int state = 0; + + /* calculate expected state,ignoring low bits */ + if (mddev->bitmap && mddev->bitmap_offset) + state |= (1 << MD_SB_BITMAP_PRESENT); if (mddev->major_version != info->major_version || mddev->minor_version != info->minor_version || @@ -2536,12 +2573,16 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) mddev->level != info->level || /* mddev->layout != info->layout || */ !mddev->persistent != info->not_persistent|| - mddev->chunk_size != info->chunk_size ) + mddev->chunk_size != info->chunk_size || + /* ignore bottom 8 bits of state, and allow SB_BITMAP_PRESENT to change */ + ((state^info->state) & 0xfffffe00) + ) return -EINVAL; /* Check there is only one change */ if (mddev->size != info->size) cnt++; if (mddev->raid_disks != info->raid_disks) cnt++; if (mddev->layout != info->layout) cnt++; + if ((state ^ info->state) & (1<<MD_SB_BITMAP_PRESENT)) cnt++; if (cnt == 0) return 0; if (cnt > 1) return -EINVAL; @@ -2620,6 +2661,35 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) } } } + if ((state ^ info->state) & (1<<MD_SB_BITMAP_PRESENT)) { + if (mddev->pers->quiesce == NULL) + return -EINVAL; + if (mddev->recovery || mddev->sync_thread) + return -EBUSY; + if (info->state & (1<<MD_SB_BITMAP_PRESENT)) { + /* add the bitmap */ + if (mddev->bitmap) + return -EEXIST; + if (mddev->default_bitmap_offset == 0) + return -EINVAL; + mddev->bitmap_offset = mddev->default_bitmap_offset; + mddev->pers->quiesce(mddev, 1); + rv = bitmap_create(mddev); + if (rv) + bitmap_destroy(mddev); + mddev->pers->quiesce(mddev, 0); + } else { + /* remove the bitmap */ + if (!mddev->bitmap) + return -ENOENT; + if (mddev->bitmap->file) + return -EINVAL; + mddev->pers->quiesce(mddev, 1); + bitmap_destroy(mddev); + mddev->pers->quiesce(mddev, 0); + mddev->bitmap_offset = 0; + } + } md_update_sb(mddev); return rv; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index ace41c571aeb3..ba643e4bfac99 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1565,6 +1565,35 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks) return 0; } +void raid1_quiesce(mddev_t *mddev, int state) +{ + conf_t *conf = mddev_to_conf(mddev); + + switch(state) { + case 0: + spin_lock_irq(&conf->resync_lock); + conf->barrier++; + wait_event_lock_irq(conf->wait_idle, !conf->nr_pending, + conf->resync_lock, raid1_unplug(mddev->queue)); + spin_unlock_irq(&conf->resync_lock); + break; + case 1: + spin_lock_irq(&conf->resync_lock); + conf->barrier--; + spin_unlock_irq(&conf->resync_lock); + wake_up(&conf->wait_resume); + wake_up(&conf->wait_idle); + break; + } + if (mddev->thread) { + if (mddev->bitmap) + mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ; + else + mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; + md_wakeup_thread(mddev->thread); + } +} + static mdk_personality_t raid1_personality = { @@ -1581,6 +1610,7 @@ static mdk_personality_t raid1_personality = .sync_request = sync_request, .resize = raid1_resize, .reshape = raid1_reshape, + .quiesce = raid1_quiesce, }; static int __init raid_init(void) diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 8c14ba565a45b..817062bf73524 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -278,6 +278,10 @@ struct mddev_s * start of bitmap. May be * negative, but not '0' */ + long default_bitmap_offset; /* this is the offset to use when + * hot-adding a bitmap. It should + * eventually be settable by sysfs. + */ struct list_head all_mddevs; }; @@ -314,6 +318,12 @@ struct mdk_personality_s int (*resize) (mddev_t *mddev, sector_t sectors); int (*reshape) (mddev_t *mddev, int raid_disks); int (*reconfig) (mddev_t *mddev, int layout, int chunk_size); + /* quiesce moves between quiescence states + * 0 - fully active + * 1 - no new requests allowed + * others - reserved + */ + void (*quiesce) (mddev_t *mddev, int state); }; -- GitLab From 8ddf9efe6708f3674f0ddfeb6425fd27bea109a2 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:45 -0700 Subject: [PATCH 307/563] [PATCH] md: support write-mostly device in raid1 This allows a device in a raid1 to be marked as "write mostly". Read requests will only be sent if there is no other option. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 18 ++++++++++ drivers/md/raid1.c | 76 ++++++++++++++++++++++++++------------- include/linux/raid/md_k.h | 3 ++ include/linux/raid/md_p.h | 11 ++++-- 4 files changed, 82 insertions(+), 26 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index ae654466dc239..f1ac356e656d6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -670,6 +670,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) if (mddev->level != LEVEL_MULTIPATH) { rdev->faulty = 0; + rdev->flags = 0; desc = sb->disks + rdev->desc_nr; if (desc->state & (1<<MD_DISK_FAULTY)) @@ -679,6 +680,8 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) rdev->in_sync = 1; rdev->raid_disk = desc->raid_disk; } + if (desc->state & (1<<MD_DISK_WRITEMOSTLY)) + set_bit(WriteMostly, &rdev->flags); } else /* MULTIPATH are always insync */ rdev->in_sync = 1; return 0; @@ -777,6 +780,8 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) spare++; working++; } + if (test_bit(WriteMostly, &rdev2->flags)) + d->state |= (1<<MD_DISK_WRITEMOSTLY); } /* now set the "removed" and "faulty" bits on any missing devices */ @@ -990,6 +995,9 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) rdev->raid_disk = role; break; } + rdev->flags = 0; + if (sb->devflags & WriteMostly1) + set_bit(WriteMostly, &rdev->flags); } else /* MULTIPATH are always insync */ rdev->in_sync = 1; @@ -2152,6 +2160,8 @@ static int get_disk_info(mddev_t * mddev, void __user * arg) info.state |= (1<<MD_DISK_ACTIVE); info.state |= (1<<MD_DISK_SYNC); } + if (test_bit(WriteMostly, &rdev->flags)) + info.state |= (1<<MD_DISK_WRITEMOSTLY); } else { info.major = info.minor = 0; info.raid_disk = -1; @@ -2237,6 +2247,9 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) rdev->saved_raid_disk = rdev->raid_disk; rdev->in_sync = 0; /* just to be sure */ + if (info->state & (1<<MD_DISK_WRITEMOSTLY)) + set_bit(WriteMostly, &rdev->flags); + rdev->raid_disk = -1; err = bind_rdev_to_array(rdev, mddev); if (err) @@ -2277,6 +2290,9 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) else rdev->in_sync = 0; + if (info->state & (1<<MD_DISK_WRITEMOSTLY)) + set_bit(WriteMostly, &rdev->flags); + err = bind_rdev_to_array(rdev, mddev); if (err) { export_rdev(rdev); @@ -3329,6 +3345,8 @@ static int md_seq_show(struct seq_file *seq, void *v) char b[BDEVNAME_SIZE]; seq_printf(seq, " %s[%d]", bdevname(rdev->bdev,b), rdev->desc_nr); + if (test_bit(WriteMostly, &rdev->flags)) + seq_printf(seq, "(W)"); if (rdev->faulty) { seq_printf(seq, "(F)"); continue; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index ba643e4bfac99..28839a8193f27 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -360,13 +360,14 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) { const unsigned long this_sector = r1_bio->sector; int new_disk = conf->last_used, disk = new_disk; + int wonly_disk = -1; const int sectors = r1_bio->sectors; sector_t new_distance, current_distance; - mdk_rdev_t *new_rdev, *rdev; + mdk_rdev_t *rdev; rcu_read_lock(); /* - * Check if it if we can balance. We can balance on the whole + * Check if we can balance. We can balance on the whole * device if no resync is going on, or below the resync window. * We take the first readable disk when above the resync window. */ @@ -376,11 +377,16 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) /* Choose the first operation device, for consistancy */ new_disk = 0; - while ((new_rdev=conf->mirrors[new_disk].rdev) == NULL || - !new_rdev->in_sync) { - new_disk++; - if (new_disk == conf->raid_disks) { - new_disk = -1; + for (rdev = conf->mirrors[new_disk].rdev; + !rdev || !rdev->in_sync + || test_bit(WriteMostly, &rdev->flags); + rdev = conf->mirrors[++new_disk].rdev) { + + if (rdev && rdev->in_sync) + wonly_disk = new_disk; + + if (new_disk == conf->raid_disks - 1) { + new_disk = wonly_disk; break; } } @@ -389,16 +395,26 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) /* make sure the disk is operational */ - while ((new_rdev=conf->mirrors[new_disk].rdev) == NULL || - !new_rdev->in_sync) { + for (rdev = conf->mirrors[new_disk].rdev; + !rdev || !rdev->in_sync || + test_bit(WriteMostly, &rdev->flags); + rdev = conf->mirrors[new_disk].rdev) { + + if (rdev && rdev->in_sync) + wonly_disk = new_disk; + if (new_disk <= 0) new_disk = conf->raid_disks; new_disk--; if (new_disk == disk) { - new_disk = -1; - goto rb_out; + new_disk = wonly_disk; + break; } } + + if (new_disk < 0) + goto rb_out; + disk = new_disk; /* now disk == new_disk == starting point for search */ @@ -419,37 +435,41 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) disk = conf->raid_disks; disk--; - if ((rdev=conf->mirrors[disk].rdev) == NULL || - !rdev->in_sync) + rdev = conf->mirrors[disk].rdev; + + if (!rdev || + !rdev->in_sync || + test_bit(WriteMostly, &rdev->flags)) continue; if (!atomic_read(&rdev->nr_pending)) { new_disk = disk; - new_rdev = rdev; break; } new_distance = abs(this_sector - conf->mirrors[disk].head_position); if (new_distance < current_distance) { current_distance = new_distance; new_disk = disk; - new_rdev = rdev; } } while (disk != conf->last_used); -rb_out: + rb_out: if (new_disk >= 0) { - conf->next_seq_sect = this_sector + sectors; - conf->last_used = new_disk; - atomic_inc(&new_rdev->nr_pending); - if (!new_rdev->in_sync) { + rdev = conf->mirrors[new_disk].rdev; + if (!rdev) + goto retry; + atomic_inc(&rdev->nr_pending); + if (!rdev->in_sync) { /* cannot risk returning a device that failed * before we inc'ed nr_pending */ - atomic_dec(&new_rdev->nr_pending); + atomic_dec(&rdev->nr_pending); goto retry; } + conf->next_seq_sect = this_sector + sectors; + conf->last_used = new_disk; } rcu_read_unlock(); @@ -1109,6 +1129,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i sector_t max_sector, nr_sectors; int disk; int i; + int wonly; int write_targets = 0; int sync_blocks; int still_degraded = 0; @@ -1164,14 +1185,21 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i */ disk = conf->last_used; /* make sure disk is operational */ - + wonly = disk; while (conf->mirrors[disk].rdev == NULL || - !conf->mirrors[disk].rdev->in_sync) { + !conf->mirrors[disk].rdev->in_sync || + test_bit(WriteMostly, &conf->mirrors[disk].rdev->flags) + ) { + if (conf->mirrors[disk].rdev && + conf->mirrors[disk].rdev->in_sync) + wonly = disk; if (disk <= 0) disk = conf->raid_disks; disk--; - if (disk == conf->last_used) + if (disk == conf->last_used) { + disk = wonly; break; + } } conf->last_used = disk; atomic_inc(&conf->mirrors[disk].rdev->nr_pending); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 817062bf73524..7ef78e15ce04a 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -181,6 +181,9 @@ struct mdk_rdev_s int faulty; /* if faulty do not issue IO requests */ int in_sync; /* device is a full member of the array */ + unsigned long flags; /* Should include faulty and in_sync here. */ +#define WriteMostly 4 /* Avoid reading if at all possible */ + int desc_nr; /* descriptor index in the superblock */ int raid_disk; /* role of device in array */ int saved_raid_disk; /* role that device used to have in the diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h index dc65cd4354942..4f047f84fb1fd 100644 --- a/include/linux/raid/md_p.h +++ b/include/linux/raid/md_p.h @@ -79,6 +79,11 @@ #define MD_DISK_SYNC 2 /* disk is in sync with the raid set */ #define MD_DISK_REMOVED 3 /* disk is in sync with the raid set */ +#define MD_DISK_WRITEMOSTLY 9 /* disk is "write-mostly" is RAID1 config. + * read requests will only be sent here in + * dire need + */ + typedef struct mdp_device_descriptor_s { __u32 number; /* 0 Device number in the entire set */ __u32 major; /* 1 Device major number */ @@ -193,7 +198,7 @@ struct mdp_superblock_1 { __u64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ __u32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ - __u32 layout; /* only for raid5 currently */ + __u32 layout; /* only for raid5 and raid10 currently */ __u64 size; /* used size of component devices, in 512byte sectors */ __u32 chunksize; /* in 512byte sectors */ @@ -212,7 +217,9 @@ struct mdp_superblock_1 { __u32 dev_number; /* permanent identifier of this device - not role in raid */ __u32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */ __u8 device_uuid[16]; /* user-space setable, ignored by kernel */ - __u8 pad2[64-56]; /* set to 0 when writing */ + __u8 devflags; /* per-device flags. Only one defined...*/ +#define WriteMostly1 1 /* mask for writemostly flag in above */ + __u8 pad2[64-57]; /* set to 0 when writing */ /* array state information - 64 bytes */ __u64 utime; /* 40 bits second, 24 btes microseconds */ -- GitLab From 4b6d287f627b5fb6a49f78f9e81649ff98c62bb7 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:47 -0700 Subject: [PATCH 308/563] [PATCH] md: add write-behind support for md/raid1 If a device is flagged 'WriteMostly' and the array has a bitmap, and the bitmap superblock indicates that write_behind is allowed, then write_behind is enabled for WriteMostly devices. Write requests will be acknowledges as complete to the caller (via b_end_io) when all non-WriteMostly devices have completed the write, but will not be cleared from the bitmap until all devices complete. This requires memory allocation to make a local copy of the data being written. If there is insufficient memory, then we fall-back on normal write semantics. Signed-Off-By: Paul Clements <paul.clements@steeleye.com> Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/bitmap.c | 26 ++++++-- drivers/md/raid1.c | 124 ++++++++++++++++++++++++++++++++++-- include/linux/raid/bitmap.h | 15 +++-- include/linux/raid/md_k.h | 3 + include/linux/raid/raid1.h | 13 ++++ 5 files changed, 165 insertions(+), 16 deletions(-) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 2925219f08819..2c84de2b4ad5c 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -437,6 +437,7 @@ void bitmap_print_sb(struct bitmap *bitmap) printk(KERN_DEBUG " daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep)); printk(KERN_DEBUG " sync size: %llu KB\n", (unsigned long long)le64_to_cpu(sb->sync_size)/2); + printk(KERN_DEBUG "max write behind: %d\n", le32_to_cpu(sb->write_behind)); kunmap(bitmap->sb_page); } @@ -445,7 +446,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) { char *reason = NULL; bitmap_super_t *sb; - unsigned long chunksize, daemon_sleep; + unsigned long chunksize, daemon_sleep, write_behind; unsigned long bytes_read; unsigned long long events; int err = -EINVAL; @@ -474,6 +475,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) chunksize = le32_to_cpu(sb->chunksize); daemon_sleep = le32_to_cpu(sb->daemon_sleep); + write_behind = le32_to_cpu(sb->write_behind); /* verify that the bitmap-specific fields are valid */ if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) @@ -485,7 +487,9 @@ static int bitmap_read_sb(struct bitmap *bitmap) else if ((1 << ffz(~chunksize)) != chunksize) reason = "bitmap chunksize not a power of 2"; else if (daemon_sleep < 1 || daemon_sleep > 15) - reason = "daemon sleep period out of range"; + reason = "daemon sleep period out of range (1-15s)"; + else if (write_behind > COUNTER_MAX) + reason = "write-behind limit out of range (0 - 16383)"; if (reason) { printk(KERN_INFO "%s: invalid bitmap file superblock: %s\n", bmname(bitmap), reason); @@ -518,6 +522,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) /* assign fields using values from superblock */ bitmap->chunksize = chunksize; bitmap->daemon_sleep = daemon_sleep; + bitmap->max_write_behind = write_behind; bitmap->flags |= sb->state; bitmap->events_cleared = le64_to_cpu(sb->events_cleared); if (sb->state & BITMAP_STALE) @@ -1282,9 +1287,16 @@ static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, } } -int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors) +int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, int behind) { if (!bitmap) return 0; + + if (behind) { + atomic_inc(&bitmap->behind_writes); + PRINTK(KERN_DEBUG "inc write-behind count %d/%d\n", + atomic_read(&bitmap->behind_writes), bitmap->max_write_behind); + } + while (sectors) { int blocks; bitmap_counter_t *bmc; @@ -1319,9 +1331,15 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect } void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, - int success) + int success, int behind) { if (!bitmap) return; + if (behind) { + atomic_dec(&bitmap->behind_writes); + PRINTK(KERN_DEBUG "dec write-behind count %d/%d\n", + atomic_read(&bitmap->behind_writes), bitmap->max_write_behind); + } + while (sectors) { int blocks; unsigned long flags; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 28839a8193f27..ba7f5f2561619 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -222,8 +222,17 @@ static void raid_end_bio_io(r1bio_t *r1_bio) { struct bio *bio = r1_bio->master_bio; - bio_endio(bio, bio->bi_size, - test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO); + /* if nobody has done the final endio yet, do it now */ + if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) { + PRINTK(KERN_DEBUG "raid1: sync end %s on sectors %llu-%llu\n", + (bio_data_dir(bio) == WRITE) ? "write" : "read", + (unsigned long long) bio->bi_sector, + (unsigned long long) bio->bi_sector + + (bio->bi_size >> 9) - 1); + + bio_endio(bio, bio->bi_size, + test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO); + } free_r1bio(r1_bio); } @@ -292,7 +301,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); - int mirror; + int mirror, behind; conf_t *conf = mddev_to_conf(r1_bio->mddev); if (bio->bi_size) @@ -323,16 +332,46 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int update_head_pos(mirror, r1_bio); + behind = test_bit(R1BIO_BehindIO, &r1_bio->state); + if (behind) { + if (test_bit(WriteMostly, &conf->mirrors[mirror].rdev->flags)) + atomic_dec(&r1_bio->behind_remaining); + + /* In behind mode, we ACK the master bio once the I/O has safely + * reached all non-writemostly disks. Setting the Returned bit + * ensures that this gets done only once -- we don't ever want to + * return -EIO here, instead we'll wait */ + + if (atomic_read(&r1_bio->behind_remaining) >= (atomic_read(&r1_bio->remaining)-1) && + test_bit(R1BIO_Uptodate, &r1_bio->state)) { + /* Maybe we can return now */ + if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) { + struct bio *mbio = r1_bio->master_bio; + PRINTK(KERN_DEBUG "raid1: behind end write sectors %llu-%llu\n", + (unsigned long long) mbio->bi_sector, + (unsigned long long) mbio->bi_sector + + (mbio->bi_size >> 9) - 1); + bio_endio(mbio, mbio->bi_size, 0); + } + } + } /* * * Let's see if all mirrored write operations have finished * already. */ if (atomic_dec_and_test(&r1_bio->remaining)) { + if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { + /* free extra copy of the data pages */ + int i = bio->bi_vcnt; + while (i--) + __free_page(bio->bi_io_vec[i].bv_page); + } /* clear the bitmap if all writes complete successfully */ bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, r1_bio->sectors, - !test_bit(R1BIO_Degraded, &r1_bio->state)); + !test_bit(R1BIO_Degraded, &r1_bio->state), + behind); md_write_end(r1_bio->mddev); raid_end_bio_io(r1_bio); } @@ -562,6 +601,39 @@ static void device_barrier(conf_t *conf, sector_t sect) spin_unlock_irq(&conf->resync_lock); } +/* duplicate the data pages for behind I/O */ +static struct page **alloc_behind_pages(struct bio *bio) +{ + int i; + struct bio_vec *bvec; + struct page **pages = kmalloc(bio->bi_vcnt * sizeof(struct page *), + GFP_NOIO); + if (unlikely(!pages)) + goto do_sync_io; + + memset(pages, 0, bio->bi_vcnt * sizeof(struct page *)); + + bio_for_each_segment(bvec, bio, i) { + pages[i] = alloc_page(GFP_NOIO); + if (unlikely(!pages[i])) + goto do_sync_io; + memcpy(kmap(pages[i]) + bvec->bv_offset, + kmap(bvec->bv_page) + bvec->bv_offset, bvec->bv_len); + kunmap(pages[i]); + kunmap(bvec->bv_page); + } + + return pages; + +do_sync_io: + if (pages) + for (i = 0; i < bio->bi_vcnt && pages[i]; i++) + __free_page(pages[i]); + kfree(pages); + PRINTK("%dB behind alloc failed, doing sync I/O\n", bio->bi_size); + return NULL; +} + static int make_request(request_queue_t *q, struct bio * bio) { mddev_t *mddev = q->queuedata; @@ -574,6 +646,7 @@ static int make_request(request_queue_t *q, struct bio * bio) struct bitmap *bitmap = mddev->bitmap; unsigned long flags; struct bio_list bl; + struct page **behind_pages = NULL; if (unlikely(bio_barrier(bio))) { bio_endio(bio, bio->bi_size, -EOPNOTSUPP); @@ -613,8 +686,6 @@ static int make_request(request_queue_t *q, struct bio * bio) r1_bio->mddev = mddev; r1_bio->sector = bio->bi_sector; - r1_bio->state = 0; - if (bio_data_dir(bio) == READ) { /* * read balancing logic: @@ -675,13 +746,22 @@ static int make_request(request_queue_t *q, struct bio * bio) } rcu_read_unlock(); + BUG_ON(targets == 0); /* we never fail the last device */ + if (targets < conf->raid_disks) { /* array is degraded, we will not clear the bitmap * on I/O completion (see raid1_end_write_request) */ set_bit(R1BIO_Degraded, &r1_bio->state); } + /* do behind I/O ? */ + if (bitmap && + atomic_read(&bitmap->behind_writes) < bitmap->max_write_behind && + (behind_pages = alloc_behind_pages(bio)) != NULL) + set_bit(R1BIO_BehindIO, &r1_bio->state); + atomic_set(&r1_bio->remaining, 0); + atomic_set(&r1_bio->behind_remaining, 0); bio_list_init(&bl); for (i = 0; i < disks; i++) { @@ -698,12 +778,31 @@ static int make_request(request_queue_t *q, struct bio * bio) mbio->bi_rw = WRITE; mbio->bi_private = r1_bio; + if (behind_pages) { + struct bio_vec *bvec; + int j; + + /* Yes, I really want the '__' version so that + * we clear any unused pointer in the io_vec, rather + * than leave them unchanged. This is important + * because when we come to free the pages, we won't + * know the originial bi_idx, so we just free + * them all + */ + __bio_for_each_segment(bvec, mbio, j, 0) + bvec->bv_page = behind_pages[j]; + if (test_bit(WriteMostly, &conf->mirrors[i].rdev->flags)) + atomic_inc(&r1_bio->behind_remaining); + } + atomic_inc(&r1_bio->remaining); bio_list_add(&bl, mbio); } + kfree(behind_pages); /* the behind pages are attached to the bios now */ - bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors); + bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors, + test_bit(R1BIO_BehindIO, &r1_bio->state)); spin_lock_irqsave(&conf->device_lock, flags); bio_list_merge(&conf->pending_bio_list, &bl); bio_list_init(&bl); @@ -1471,6 +1570,17 @@ static int run(mddev_t *mddev) static int stop(mddev_t *mddev) { conf_t *conf = mddev_to_conf(mddev); + struct bitmap *bitmap = mddev->bitmap; + int behind_wait = 0; + + /* wait for behind writes to complete */ + while (bitmap && atomic_read(&bitmap->behind_writes) > 0) { + behind_wait++; + printk(KERN_INFO "raid1: behind writes in progress on device %s, waiting to stop (%d)\n", mdname(mddev), behind_wait); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); /* wait a second */ + /* need to kick something here to make sure I/O goes? */ + } md_unregister_thread(mddev->thread); mddev->thread = NULL; diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h index 4bf1659f8aa87..9de99198caf10 100644 --- a/include/linux/raid/bitmap.h +++ b/include/linux/raid/bitmap.h @@ -7,7 +7,7 @@ #define BITMAP_H 1 #define BITMAP_MAJOR 3 -#define BITMAP_MINOR 38 +#define BITMAP_MINOR 39 /* * in-memory bitmap: @@ -147,8 +147,9 @@ typedef struct bitmap_super_s { __u32 state; /* 48 bitmap state information */ __u32 chunksize; /* 52 the bitmap chunk size in bytes */ __u32 daemon_sleep; /* 56 seconds between disk flushes */ + __u32 write_behind; /* 60 number of outstanding write-behind writes */ - __u8 pad[256 - 60]; /* set to zero */ + __u8 pad[256 - 64]; /* set to zero */ } bitmap_super_t; /* notes: @@ -226,6 +227,9 @@ struct bitmap { unsigned long flags; + unsigned long max_write_behind; /* write-behind mode */ + atomic_t behind_writes; + /* * the bitmap daemon - periodically wakes up and sweeps the bitmap * file, cleaning up bits and flushing out pages to disk as necessary @@ -260,9 +264,10 @@ int bitmap_setallbits(struct bitmap *bitmap); void bitmap_write_all(struct bitmap *bitmap); /* these are exported */ -int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors); -void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, - int success); +int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, + unsigned long sectors, int behind); +void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, + unsigned long sectors, int success, int behind); int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int degraded); void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted); void bitmap_close_sync(struct bitmap *bitmap); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 7ef78e15ce04a..2514e5fcda7f7 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -275,6 +275,9 @@ struct mddev_s atomic_t writes_pending; request_queue_t *queue; /* for plugging ... */ + atomic_t write_behind; /* outstanding async IO */ + unsigned int max_write_behind; /* 0 = sync */ + struct bitmap *bitmap; /* the bitmap for the device */ struct file *bitmap_file; /* the bitmap file */ long bitmap_offset; /* offset from superblock of diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h index 9d93cf12e8901..60e19b667548f 100644 --- a/include/linux/raid/raid1.h +++ b/include/linux/raid/raid1.h @@ -80,6 +80,9 @@ struct r1bio_s { atomic_t remaining; /* 'have we finished' count, * used from IRQ handlers */ + atomic_t behind_remaining; /* number of write-behind ios remaining + * in this BehindIO request + */ sector_t sector; int sectors; unsigned long state; @@ -107,4 +110,14 @@ struct r1bio_s { #define R1BIO_Uptodate 0 #define R1BIO_IsSync 1 #define R1BIO_Degraded 2 +#define R1BIO_BehindIO 3 +/* For write-behind requests, we call bi_end_io when + * the last non-write-behind device completes, providing + * any write was successful. Otherwise we call when + * any write-behind write succeeds, otherwise we call + * with failure when last write completes (and all failed). + * Record that bi_end_io was called with this flag... + */ +#define R1BIO_Returned 4 + #endif -- GitLab From 15945fee6f09bff1f86b1a735b5888dc59cf38e3 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:47 -0700 Subject: [PATCH 309/563] [PATCH] md: support md/linear array with components greater than 2 terabytes. linear currently uses division by the size of the smallest componenet device to find which device a request goes to. If that smallest device is larger than 2 terabytes, then the division will not work on some systems. So we introduce a pre-shift, and take care not to make the hash table too large, much like the code in raid0. Also get rid of conf->nr_zones, which is not needed. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/linear.c | 95 ++++++++++++++++++++++++++----------- include/linux/raid/linear.h | 4 +- 2 files changed, 68 insertions(+), 31 deletions(-) diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 4991ba543368a..bb279fad2fd27 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -38,7 +38,8 @@ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector) /* * sector_div(a,b) returns the remainer and sets a to a/b */ - (void)sector_div(block, conf->smallest->size); + block >>= conf->preshift; + (void)sector_div(block, conf->hash_spacing); hash = conf->hash_table[block]; while ((sector>>1) >= (hash->size + hash->offset)) @@ -47,7 +48,7 @@ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector) } /** - * linear_mergeable_bvec -- tell bio layer if a two requests can be merged + * linear_mergeable_bvec -- tell bio layer if two requests can be merged * @q: request queue * @bio: the buffer head that's been built up so far * @biovec: the request that could be merged to it. @@ -116,7 +117,7 @@ static int linear_run (mddev_t *mddev) dev_info_t **table; mdk_rdev_t *rdev; int i, nb_zone, cnt; - sector_t start; + sector_t min_spacing; sector_t curr_offset; struct list_head *tmp; @@ -127,11 +128,6 @@ static int linear_run (mddev_t *mddev) memset(conf, 0, sizeof(*conf) + mddev->raid_disks*sizeof(dev_info_t)); mddev->private = conf; - /* - * Find the smallest device. - */ - - conf->smallest = NULL; cnt = 0; mddev->array_size = 0; @@ -159,8 +155,6 @@ static int linear_run (mddev_t *mddev) disk->size = rdev->size; mddev->array_size += rdev->size; - if (!conf->smallest || (disk->size < conf->smallest->size)) - conf->smallest = disk; cnt++; } if (cnt != mddev->raid_disks) { @@ -168,6 +162,36 @@ static int linear_run (mddev_t *mddev) goto out; } + min_spacing = mddev->array_size; + sector_div(min_spacing, PAGE_SIZE/sizeof(struct dev_info *)); + + /* min_spacing is the minimum spacing that will fit the hash + * table in one PAGE. This may be much smaller than needed. + * We find the smallest non-terminal set of consecutive devices + * that is larger than min_spacing as use the size of that as + * the actual spacing + */ + conf->hash_spacing = mddev->array_size; + for (i=0; i < cnt-1 ; i++) { + sector_t sz = 0; + int j; + for (j=i; i<cnt-1 && sz < min_spacing ; j++) + sz += conf->disks[j].size; + if (sz >= min_spacing && sz < conf->hash_spacing) + conf->hash_spacing = sz; + } + + /* hash_spacing may be too large for sector_div to work with, + * so we might need to pre-shift + */ + conf->preshift = 0; + if (sizeof(sector_t) > sizeof(u32)) { + sector_t space = conf->hash_spacing; + while (space > (sector_t)(~(u32)0)) { + space >>= 1; + conf->preshift++; + } + } /* * This code was restructured to work around a gcc-2.95.3 internal * compiler error. Alter it with care. @@ -177,39 +201,52 @@ static int linear_run (mddev_t *mddev) unsigned round; unsigned long base; - sz = mddev->array_size; - base = conf->smallest->size; + sz = mddev->array_size >> conf->preshift; + sz += 1; /* force round-up */ + base = conf->hash_spacing >> conf->preshift; round = sector_div(sz, base); - nb_zone = conf->nr_zones = sz + (round ? 1 : 0); + nb_zone = sz + (round ? 1 : 0); } - - conf->hash_table = kmalloc (sizeof (dev_info_t*) * nb_zone, + BUG_ON(nb_zone > PAGE_SIZE / sizeof(struct dev_info *)); + + conf->hash_table = kmalloc (sizeof (struct dev_info *) * nb_zone, GFP_KERNEL); if (!conf->hash_table) goto out; /* * Here we generate the linear hash table + * First calculate the device offsets. */ + conf->disks[0].offset = 0; + for (i=1; i<mddev->raid_disks; i++) + conf->disks[i].offset = + conf->disks[i-1].offset + + conf->disks[i-1].size; + table = conf->hash_table; - start = 0; curr_offset = 0; - for (i = 0; i < cnt; i++) { - dev_info_t *disk = conf->disks + i; + i = 0; + for (curr_offset = 0; + curr_offset < mddev->array_size; + curr_offset += conf->hash_spacing) { - disk->offset = curr_offset; - curr_offset += disk->size; + while (i < mddev->raid_disks-1 && + curr_offset >= conf->disks[i+1].offset) + i++; - /* 'curr_offset' is the end of this disk - * 'start' is the start of table + *table ++ = conf->disks + i; + } + + if (conf->preshift) { + conf->hash_spacing >>= conf->preshift; + /* round hash_spacing up so that when we divide by it, + * we err on the side of "too-low", which is safest. */ - while (start < curr_offset) { - *table++ = disk; - start += conf->smallest->size; - } + conf->hash_spacing++; } - if (table-conf->hash_table != nb_zone) - BUG(); + + BUG_ON(table - conf->hash_table > nb_zone); blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); mddev->queue->unplug_fn = linear_unplug; @@ -299,7 +336,7 @@ static void linear_status (struct seq_file *seq, mddev_t *mddev) sector_t s = 0; seq_printf(seq, " "); - for (j = 0; j < conf->nr_zones; j++) + for (j = 0; j < mddev->raid_disks; j++) { char b[BDEVNAME_SIZE]; s += conf->smallest_size; diff --git a/include/linux/raid/linear.h b/include/linux/raid/linear.h index e04c4fe45b533..7eaf290e10e75 100644 --- a/include/linux/raid/linear.h +++ b/include/linux/raid/linear.h @@ -14,8 +14,8 @@ typedef struct dev_info dev_info_t; struct linear_private_data { dev_info_t **hash_table; - dev_info_t *smallest; - int nr_zones; + sector_t hash_spacing; + int preshift; /* shift before dividing by hash_spacing */ dev_info_t disks[0]; }; -- GitLab From 9e6603da9b9cfb14a6aca3845227f8c59f7eeb9b Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:48 -0700 Subject: [PATCH 310/563] [PATCH] md: raid1_quiesce is back to front, fix it. A state of 0 mean 'not quiesced' A state of 1 means 'is quiesced' The original code got this wrong. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/raid1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index ba7f5f2561619..bfe78571586b9 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1708,14 +1708,14 @@ void raid1_quiesce(mddev_t *mddev, int state) conf_t *conf = mddev_to_conf(mddev); switch(state) { - case 0: + case 1: spin_lock_irq(&conf->resync_lock); conf->barrier++; wait_event_lock_irq(conf->wait_idle, !conf->nr_pending, conf->resync_lock, raid1_unplug(mddev->queue)); spin_unlock_irq(&conf->resync_lock); break; - case 1: + case 0: spin_lock_irq(&conf->resync_lock); conf->barrier--; spin_unlock_irq(&conf->resync_lock); -- GitLab From 585f0dd5a955c420ff3af5193aa07d6f789bf81a Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:49 -0700 Subject: [PATCH 311/563] [PATCH] md: make sure bitmap_daemon_work actually does work. The 'lastrun' time wasn't being initialised, so it could be half a jiffie-cycle before it seemed to be time to do work again. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/bitmap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 2c84de2b4ad5c..f0f510c134101 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -522,6 +522,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) /* assign fields using values from superblock */ bitmap->chunksize = chunksize; bitmap->daemon_sleep = daemon_sleep; + bitmap->daemon_lastrun = jiffies; bitmap->max_write_behind = write_behind; bitmap->flags |= sb->state; bitmap->events_cleared = le64_to_cpu(sb->events_cleared); -- GitLab From 3178b0dbdf67322f6506582e494bdf553cc85c32 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:50 -0700 Subject: [PATCH 312/563] [PATCH] md: do not set mddev->bitmap until bitmap is fully initialised When hot-adding a bitmap, bitmap_daemon_work could get called while the bitmap is being created, so don't set mddev->bitmap until the bitmap is ready. This requires freeing the bitmap inside bitmap_create if creation failed part-way through. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/bitmap.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index f0f510c134101..c971d38f3a05e 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1503,17 +1503,14 @@ void bitmap_flush(mddev_t *mddev) /* * free memory that was allocated */ -void bitmap_destroy(mddev_t *mddev) +static void bitmap_free(struct bitmap *bitmap) { unsigned long k, pages; struct bitmap_page *bp; - struct bitmap *bitmap = mddev->bitmap; if (!bitmap) /* there was no bitmap */ return; - mddev->bitmap = NULL; /* disconnect from the md device */ - /* release the bitmap file and kill the daemon */ bitmap_file_put(bitmap); @@ -1531,6 +1528,17 @@ void bitmap_destroy(mddev_t *mddev) kfree(bp); kfree(bitmap); } +void bitmap_destroy(mddev_t *mddev) +{ + struct bitmap *bitmap = mddev->bitmap; + + if (!bitmap) /* there was no bitmap */ + return; + + mddev->bitmap = NULL; /* disconnect from the md device */ + + bitmap_free(bitmap); +} /* * initialize the bitmap structure @@ -1561,15 +1569,15 @@ int bitmap_create(mddev_t *mddev) spin_lock_init(&bitmap->lock); bitmap->mddev = mddev; - mddev->bitmap = bitmap; spin_lock_init(&bitmap->write_lock); INIT_LIST_HEAD(&bitmap->complete_pages); init_waitqueue_head(&bitmap->write_wait); bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc, write_pool_free, NULL); + err = -ENOMEM; if (!bitmap->write_pool) - return -ENOMEM; + goto error; bitmap->file = file; bitmap->offset = mddev->bitmap_offset; @@ -1577,7 +1585,7 @@ int bitmap_create(mddev_t *mddev) /* read superblock from bitmap file (this sets bitmap->chunksize) */ err = bitmap_read_sb(bitmap); if (err) - return err; + goto error; bitmap->chunkshift = find_first_bit(&bitmap->chunksize, sizeof(bitmap->chunksize)); @@ -1601,8 +1609,9 @@ int bitmap_create(mddev_t *mddev) #else bitmap->bp = kmalloc(pages * sizeof(*bitmap->bp), GFP_KERNEL); #endif + err = -ENOMEM; if (!bitmap->bp) - return -ENOMEM; + goto error; memset(bitmap->bp, 0, pages * sizeof(*bitmap->bp)); bitmap->flags |= BITMAP_ACTIVE; @@ -1617,16 +1626,22 @@ int bitmap_create(mddev_t *mddev) err = bitmap_init_from_disk(bitmap, start); if (err) - return err; + goto error; printk(KERN_INFO "created bitmap (%lu pages) for device %s\n", pages, bmname(bitmap)); + mddev->bitmap = bitmap; + /* kick off the bitmap daemons */ err = bitmap_start_daemons(bitmap); if (err) return err; return bitmap_update_sb(bitmap); + + error: + bitmap_free(bitmap); + return err; } /* the bitmap API -- for raid personalities */ -- GitLab From 7b1e35f6d666693e8f376ce02242efca3ec09aaf Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:50 -0700 Subject: [PATCH 313/563] [PATCH] md: allow hot-adding devices to arrays with non-persistant superblocks. It is possibly (and occasionally useful) to have a raid1 without persistent superblocks. The code in add_new_disk for adding a device to such an array always tries to read a superblock. This will obviously fail. So do the appropriate test and call md_import_device with appropriate args. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index f1ac356e656d6..866c704e008a1 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2226,8 +2226,11 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) mdname(mddev)); return -EINVAL; } - rdev = md_import_device(dev, mddev->major_version, - mddev->minor_version); + if (mddev->persistent) + rdev = md_import_device(dev, mddev->major_version, + mddev->minor_version); + else + rdev = md_import_device(dev, -1, -1); if (IS_ERR(rdev)) { printk(KERN_WARNING "md: md_import_device returned %ld\n", -- GitLab From 71c0805cb48462c99fbe0e5fcc6c12d7b9929c09 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:51 -0700 Subject: [PATCH 314/563] [PATCH] md: allow md to load a superblock with feature-bit '1' set As this is used to flag an internal bitmap. Also, introduce symbolic names for feature bits. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 6 +++--- include/linux/raid/md_p.h | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 866c704e008a1..1be3f2de396b4 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -875,7 +875,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) sb->major_version != cpu_to_le32(1) || le32_to_cpu(sb->max_dev) > (4096-256)/2 || le64_to_cpu(sb->super_offset) != (rdev->sb_offset<<1) || - sb->feature_map != 0) + (le32_to_cpu(sb->feature_map) & ~MD_FEATURE_ALL) != 0) return -EINVAL; if (calc_sb_1_csum(sb) != sb->sb_csum) { @@ -954,7 +954,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->max_disks = (4096-256)/2; - if ((le32_to_cpu(sb->feature_map) & 1) && + if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) && mddev->bitmap_file == NULL ) { if (mddev->level != 1) { printk(KERN_WARNING "md: bitmaps only supported for raid1\n"); @@ -1029,7 +1029,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) if (mddev->bitmap && mddev->bitmap_file == NULL) { sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); - sb->feature_map = cpu_to_le32(1); + sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET); } max_dev = 0; diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h index 4f047f84fb1fd..c100fa5d4bfa0 100644 --- a/include/linux/raid/md_p.h +++ b/include/linux/raid/md_p.h @@ -238,5 +238,10 @@ struct mdp_superblock_1 { __u16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ }; +/* feature_map bits */ +#define MD_FEATURE_BITMAP_OFFSET 1 + +#define MD_FEATURE_ALL 1 + #endif -- GitLab From ab904d634625ef8dc590240b7ee06c7b724e636b Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:52 -0700 Subject: [PATCH 315/563] [PATCH] md: fix bitmap/read_sb_page so that it handles errors properly. read_sb_page() assumed that if sync_page_io fails, the device would be marked faultly. However it isn't. So in the face of error, read_sb_page would loop forever. Redo the logic so that this cannot happen. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/bitmap.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index c971d38f3a05e..90fe70d76a316 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -270,19 +270,20 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde if (!page) return ERR_PTR(-ENOMEM); - do { - ITERATE_RDEV(mddev, rdev, tmp) - if (rdev->in_sync && !rdev->faulty) - goto found; - return ERR_PTR(-EIO); - found: + ITERATE_RDEV(mddev, rdev, tmp) { + if (! rdev->in_sync || rdev->faulty) + continue; + target = (rdev->sb_offset << 1) + offset + index * (PAGE_SIZE/512); - } while (!sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)); + if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) { + page->index = index; + return page; + } + } + return ERR_PTR(-EIO); - page->index = index; - return page; } static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wait) -- GitLab From 773f7834425e83144c95fbbc553ced3c2b74b828 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:53 -0700 Subject: [PATCH 316/563] [PATCH] md: remove old cruft from md_k.h header file These inlines haven't been used for ages, they should go. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/raid/md_k.h | 64 --------------------------------------- 1 file changed, 64 deletions(-) diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 2514e5fcda7f7..8042f55dd3237 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -85,70 +85,6 @@ typedef struct mdk_rdev_s mdk_rdev_t; #define MAX_CHUNK_SIZE (4096*1024) -/* - * default readahead - */ - -static inline int disk_faulty(mdp_disk_t * d) -{ - return d->state & (1 << MD_DISK_FAULTY); -} - -static inline int disk_active(mdp_disk_t * d) -{ - return d->state & (1 << MD_DISK_ACTIVE); -} - -static inline int disk_sync(mdp_disk_t * d) -{ - return d->state & (1 << MD_DISK_SYNC); -} - -static inline int disk_spare(mdp_disk_t * d) -{ - return !disk_sync(d) && !disk_active(d) && !disk_faulty(d); -} - -static inline int disk_removed(mdp_disk_t * d) -{ - return d->state & (1 << MD_DISK_REMOVED); -} - -static inline void mark_disk_faulty(mdp_disk_t * d) -{ - d->state |= (1 << MD_DISK_FAULTY); -} - -static inline void mark_disk_active(mdp_disk_t * d) -{ - d->state |= (1 << MD_DISK_ACTIVE); -} - -static inline void mark_disk_sync(mdp_disk_t * d) -{ - d->state |= (1 << MD_DISK_SYNC); -} - -static inline void mark_disk_spare(mdp_disk_t * d) -{ - d->state = 0; -} - -static inline void mark_disk_removed(mdp_disk_t * d) -{ - d->state = (1 << MD_DISK_FAULTY) | (1 << MD_DISK_REMOVED); -} - -static inline void mark_disk_inactive(mdp_disk_t * d) -{ - d->state &= ~(1 << MD_DISK_ACTIVE); -} - -static inline void mark_disk_nonsync(mdp_disk_t * d) -{ - d->state &= ~(1 << MD_DISK_SYNC); -} - /* * MD's 'extended' device */ -- GitLab From 0002b2718dd04da67c21f8a7830de8d95a9b0345 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:53 -0700 Subject: [PATCH 317/563] [PATCH] md: limit size of sb read/written to appropriate amount version-1 superblocks are not (normally) 4K long, and can be of variable size. Writing the full 4K can cause corruption (but only in non-default configurations). With this patch the super-block-flavour can choose a size to read, and set a size to write based on what it finds. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 20 +++++++++++++++----- include/linux/raid/md_k.h | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 1be3f2de396b4..be7873c61b3cc 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -393,7 +393,7 @@ int sync_page_io(struct block_device *bdev, sector_t sector, int size, return ret; } -static int read_disk_sb(mdk_rdev_t * rdev) +static int read_disk_sb(mdk_rdev_t * rdev, int size) { char b[BDEVNAME_SIZE]; if (!rdev->sb_page) { @@ -404,7 +404,7 @@ static int read_disk_sb(mdk_rdev_t * rdev) return 0; - if (!sync_page_io(rdev->bdev, rdev->sb_offset<<1, MD_SB_BYTES, rdev->sb_page, READ)) + if (!sync_page_io(rdev->bdev, rdev->sb_offset<<1, size, rdev->sb_page, READ)) goto fail; rdev->sb_loaded = 1; return 0; @@ -531,7 +531,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version sb_offset = calc_dev_sboffset(rdev->bdev); rdev->sb_offset = sb_offset; - ret = read_disk_sb(rdev); + ret = read_disk_sb(rdev, MD_SB_BYTES); if (ret) return ret; ret = -EINVAL; @@ -564,6 +564,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version rdev->preferred_minor = sb->md_minor; rdev->data_offset = 0; + rdev->sb_size = MD_SB_BYTES; if (sb->level == LEVEL_MULTIPATH) rdev->desc_nr = -1; @@ -837,6 +838,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) int ret; sector_t sb_offset; char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; + int bmask; /* * Calculate the position of the superblock. @@ -865,7 +867,10 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) } rdev->sb_offset = sb_offset; - ret = read_disk_sb(rdev); + /* superblock is rarely larger than 1K, but it can be larger, + * and it is safe to read 4k, so we do that + */ + ret = read_disk_sb(rdev, 4096); if (ret) return ret; @@ -891,6 +896,11 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) rdev->preferred_minor = 0xffff; rdev->data_offset = le64_to_cpu(sb->data_offset); + rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256; + bmask = block_size(rdev->bdev)-1; + if (rdev->sb_size & bmask) + rdev-> sb_size = (rdev->sb_size | bmask)+1; + if (refdev == 0) return 1; else { @@ -1375,7 +1385,7 @@ static void md_update_sb(mddev_t * mddev) dprintk("%s ", bdevname(rdev->bdev,b)); if (!rdev->faulty) { md_super_write(mddev,rdev, - rdev->sb_offset<<1, MD_SB_BYTES, + rdev->sb_offset<<1, rdev->sb_size, rdev->sb_page); dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", bdevname(rdev->bdev,b), diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 8042f55dd3237..ebce949b14432 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -102,6 +102,7 @@ struct mdk_rdev_s int sb_loaded; sector_t data_offset; /* start of data in array */ sector_t sb_offset; + int sb_size; /* bytes in the superblock */ int preferred_minor; /* autorun support */ /* A device can be in one of three states based on two flags: -- GitLab From 72626685dc66d455742a7f215a0535c551628b9e Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:54 -0700 Subject: [PATCH 318/563] [PATCH] md: add write-intent-bitmap support to raid5 Most awkward part of this is delaying write requests until bitmap updates have been flushed. To achieve this, we have a sequence number (seq_flush) which is incremented each time the raid5 is unplugged. If the raid thread notices that this has changed, it flushes bitmap changes, and assigned the value of seq_flush to seq_write. When a write request arrives, it is given the number from seq_write, and that write request may not complete until seq_flush is larger than the saved seq number. We have a new queue for storing stripes which are waiting for a bitmap flush and an extra flag for stripes to record if the write was 'degraded' and so should not clear the a bit in the bitmap. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 3 +- drivers/md/raid5.c | 133 ++++++++++++++++++++++++++++++++++--- include/linux/raid/raid5.h | 14 +++- 3 files changed, 137 insertions(+), 13 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index be7873c61b3cc..dbf540a7fccca 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -645,7 +645,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) if (sb->state & (1<<MD_SB_BITMAP_PRESENT) && mddev->bitmap_file == NULL) { - if (mddev->level != 1) { + if (mddev->level != 1 && mddev->level != 5) { /* FIXME use a better test */ printk(KERN_WARNING "md: bitmaps only support for raid1\n"); return -EINVAL; @@ -3517,7 +3517,6 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok) */ void md_write_start(mddev_t *mddev, struct bio *bi) { - DEFINE_WAIT(w); if (bio_data_dir(bi) != WRITE) return; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index ed859e08d600f..4683ca24c0469 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -24,6 +24,8 @@ #include <linux/bitops.h> #include <asm/atomic.h> +#include <linux/raid/bitmap.h> + /* * Stripe cache */ @@ -79,8 +81,13 @@ static inline void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) if (test_bit(STRIPE_HANDLE, &sh->state)) { if (test_bit(STRIPE_DELAYED, &sh->state)) list_add_tail(&sh->lru, &conf->delayed_list); - else + else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && + conf->seq_write == sh->bm_seq) + list_add_tail(&sh->lru, &conf->bitmap_list); + else { + clear_bit(STRIPE_BIT_DELAY, &sh->state); list_add_tail(&sh->lru, &conf->handle_list); + } md_wakeup_thread(conf->mddev->thread); } else { if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { @@ -244,6 +251,9 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector spin_lock_irq(&conf->device_lock); do { + wait_event_lock_irq(conf->wait_for_stripe, + conf->quiesce == 0, + conf->device_lock, /* nothing */); sh = __find_stripe(conf, sector); if (!sh) { if (!conf->inactive_blocked) @@ -803,6 +813,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in { struct bio **bip; raid5_conf_t *conf = sh->raid_conf; + int firstwrite=0; PRINTK("adding bh b#%llu to stripe s#%llu\n", (unsigned long long)bi->bi_sector, @@ -811,9 +822,11 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in spin_lock(&sh->lock); spin_lock_irq(&conf->device_lock); - if (forwrite) + if (forwrite) { bip = &sh->dev[dd_idx].towrite; - else + if (*bip == NULL && sh->dev[dd_idx].written == NULL) + firstwrite = 1; + } else bip = &sh->dev[dd_idx].toread; while (*bip && (*bip)->bi_sector < bi->bi_sector) { if ((*bip)->bi_sector + ((*bip)->bi_size >> 9) > bi->bi_sector) @@ -836,6 +849,13 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in (unsigned long long)bi->bi_sector, (unsigned long long)sh->sector, dd_idx); + if (conf->mddev->bitmap && firstwrite) { + sh->bm_seq = conf->seq_write; + bitmap_startwrite(conf->mddev->bitmap, sh->sector, + STRIPE_SECTORS, 0); + set_bit(STRIPE_BIT_DELAY, &sh->state); + } + if (forwrite) { /* check if page is covered */ sector_t sector = sh->dev[dd_idx].sector; @@ -958,12 +978,13 @@ static void handle_stripe(struct stripe_head *sh) * need to be failed */ if (failed > 1 && to_read+to_write+written) { - spin_lock_irq(&conf->device_lock); for (i=disks; i--; ) { + int bitmap_end = 0; + spin_lock_irq(&conf->device_lock); /* fail all writes first */ bi = sh->dev[i].towrite; sh->dev[i].towrite = NULL; - if (bi) to_write--; + if (bi) { to_write--; bitmap_end = 1; } if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) wake_up(&conf->wait_for_overlap); @@ -981,6 +1002,7 @@ static void handle_stripe(struct stripe_head *sh) /* and fail all 'written' */ bi = sh->dev[i].written; sh->dev[i].written = NULL; + if (bi) bitmap_end = 1; while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); clear_bit(BIO_UPTODATE, &bi->bi_flags); @@ -1009,8 +1031,11 @@ static void handle_stripe(struct stripe_head *sh) bi = nextbi; } } + spin_unlock_irq(&conf->device_lock); + if (bitmap_end) + bitmap_endwrite(conf->mddev->bitmap, sh->sector, + STRIPE_SECTORS, 0, 0); } - spin_unlock_irq(&conf->device_lock); } if (failed > 1 && syncing) { md_done_sync(conf->mddev, STRIPE_SECTORS,0); @@ -1038,6 +1063,7 @@ static void handle_stripe(struct stripe_head *sh) test_bit(R5_UPTODATE, &dev->flags) ) { /* We can return any write requests */ struct bio *wbi, *wbi2; + int bitmap_end = 0; PRINTK("Return write for disc %d\n", i); spin_lock_irq(&conf->device_lock); wbi = dev->written; @@ -1051,7 +1077,13 @@ static void handle_stripe(struct stripe_head *sh) } wbi = wbi2; } + if (dev->towrite == NULL) + bitmap_end = 1; spin_unlock_irq(&conf->device_lock); + if (bitmap_end) + bitmap_endwrite(conf->mddev->bitmap, sh->sector, + STRIPE_SECTORS, + !test_bit(STRIPE_DEGRADED, &sh->state), 0); } } } @@ -1175,7 +1207,8 @@ static void handle_stripe(struct stripe_head *sh) } } /* now if nothing is locked, and if we have enough data, we can start a write request */ - if (locked == 0 && (rcw == 0 ||rmw == 0)) { + if (locked == 0 && (rcw == 0 ||rmw == 0) && + !test_bit(STRIPE_BIT_DELAY, &sh->state)) { PRINTK("Computing parity...\n"); compute_parity(sh, rcw==0 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE); /* now every locked buffer is ready to be written */ @@ -1231,6 +1264,7 @@ static void handle_stripe(struct stripe_head *sh) dev = &sh->dev[failed_num]; set_bit(R5_LOCKED, &dev->flags); set_bit(R5_Wantwrite, &dev->flags); + clear_bit(STRIPE_DEGRADED, &sh->state); locked++; set_bit(STRIPE_INSYNC, &sh->state); set_bit(R5_Syncio, &dev->flags); @@ -1298,6 +1332,8 @@ static void handle_stripe(struct stripe_head *sh) bi->bi_next = NULL; generic_make_request(bi); } else { + if (rw == 1) + set_bit(STRIPE_DEGRADED, &sh->state); PRINTK("skip op %ld on disc %d for sector %llu\n", bi->bi_rw, i, (unsigned long long)sh->sector); clear_bit(R5_LOCKED, &sh->dev[i].flags); @@ -1322,6 +1358,20 @@ static inline void raid5_activate_delayed(raid5_conf_t *conf) } } +static inline void activate_bit_delay(raid5_conf_t *conf) +{ + /* device_lock is held */ + struct list_head head; + list_add(&head, &conf->bitmap_list); + list_del_init(&conf->bitmap_list); + while (!list_empty(&head)) { + struct stripe_head *sh = list_entry(head.next, struct stripe_head, lru); + list_del_init(&sh->lru); + atomic_inc(&sh->count); + __release_stripe(conf, sh); + } +} + static void unplug_slaves(mddev_t *mddev) { raid5_conf_t *conf = mddev_to_conf(mddev); @@ -1354,8 +1404,10 @@ static void raid5_unplug_device(request_queue_t *q) spin_lock_irqsave(&conf->device_lock, flags); - if (blk_remove_plug(q)) + if (blk_remove_plug(q)) { + conf->seq_flush++; raid5_activate_delayed(conf); + } md_wakeup_thread(mddev->thread); spin_unlock_irqrestore(&conf->device_lock, flags); @@ -1493,10 +1545,20 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i sector_t first_sector; int raid_disks = conf->raid_disks; int data_disks = raid_disks-1; + sector_t max_sector = mddev->size << 1; + int sync_blocks; - if (sector_nr >= mddev->size <<1) { + if (sector_nr >= max_sector) { /* just being told to finish up .. nothing much to do */ unplug_slaves(mddev); + + if (mddev->curr_resync < max_sector) /* aborted */ + bitmap_end_sync(mddev->bitmap, mddev->curr_resync, + &sync_blocks, 1); + else /* compelted sync */ + conf->fullsync = 0; + bitmap_close_sync(mddev->bitmap); + return 0; } /* if there is 1 or more failed drives and we are trying @@ -1508,6 +1570,13 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i *skipped = 1; return rv; } + if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) && + !conf->fullsync && sync_blocks >= STRIPE_SECTORS) { + /* we can skip this block, and probably more */ + sync_blocks /= STRIPE_SECTORS; + *skipped = 1; + return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */ + } x = sector_nr; chunk_offset = sector_div(x, sectors_per_chunk); @@ -1525,6 +1594,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } + bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 0); spin_lock(&sh->lock); set_bit(STRIPE_SYNCING, &sh->state); clear_bit(STRIPE_INSYNC, &sh->state); @@ -1558,6 +1628,13 @@ static void raid5d (mddev_t *mddev) while (1) { struct list_head *first; + if (conf->seq_flush - conf->seq_write > 0) { + int seq = conf->seq_flush; + bitmap_unplug(mddev->bitmap); + conf->seq_write = seq; + activate_bit_delay(conf); + } + if (list_empty(&conf->handle_list) && atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD && !blk_queue_plugged(mddev->queue) && @@ -1591,7 +1668,7 @@ static void raid5d (mddev_t *mddev) PRINTK("--- raid5d inactive\n"); } -static int run (mddev_t *mddev) +static int run(mddev_t *mddev) { raid5_conf_t *conf; int raid_disk, memory; @@ -1621,6 +1698,7 @@ static int run (mddev_t *mddev) init_waitqueue_head(&conf->wait_for_overlap); INIT_LIST_HEAD(&conf->handle_list); INIT_LIST_HEAD(&conf->delayed_list); + INIT_LIST_HEAD(&conf->bitmap_list); INIT_LIST_HEAD(&conf->inactive_list); atomic_set(&conf->active_stripes, 0); atomic_set(&conf->preread_active_stripes, 0); @@ -1732,6 +1810,9 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + /* Ok, everything is just fine now */ + if (mddev->bitmap) + mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ; + mddev->queue->unplug_fn = raid5_unplug_device; mddev->queue->issue_flush_fn = raid5_issue_flush; @@ -1912,6 +1993,8 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) rdev->in_sync = 0; rdev->raid_disk = disk; found = 1; + if (rdev->saved_raid_disk != disk) + conf->fullsync = 1; p->rdev = rdev; break; } @@ -1941,6 +2024,35 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors) return 0; } +static void raid5_quiesce(mddev_t *mddev, int state) +{ + raid5_conf_t *conf = mddev_to_conf(mddev); + + switch(state) { + case 1: /* stop all writes */ + spin_lock_irq(&conf->device_lock); + conf->quiesce = 1; + wait_event_lock_irq(conf->wait_for_stripe, + atomic_read(&conf->active_stripes) == 0, + conf->device_lock, /* nothing */); + spin_unlock_irq(&conf->device_lock); + break; + + case 0: /* re-enable writes */ + spin_lock_irq(&conf->device_lock); + conf->quiesce = 0; + wake_up(&conf->wait_for_stripe); + spin_unlock_irq(&conf->device_lock); + break; + } + if (mddev->thread) { + if (mddev->bitmap) + mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ; + else + mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; + md_wakeup_thread(mddev->thread); + } +} static mdk_personality_t raid5_personality= { .name = "raid5", @@ -1955,6 +2067,7 @@ static mdk_personality_t raid5_personality= .spare_active = raid5_spare_active, .sync_request = sync_request, .resize = raid5_resize, + .quiesce = raid5_quiesce, }; static int __init raid5_init (void) diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h index d63ddcb4afadf..176fc653c2847 100644 --- a/include/linux/raid/raid5.h +++ b/include/linux/raid/raid5.h @@ -134,6 +134,7 @@ struct stripe_head { unsigned long state; /* state flags */ atomic_t count; /* nr of active thread/requests */ spinlock_t lock; + int bm_seq; /* sequence number for bitmap flushes */ struct r5dev { struct bio req; struct bio_vec vec; @@ -165,12 +166,13 @@ struct stripe_head { /* * Stripe state */ -#define STRIPE_ERROR 1 #define STRIPE_HANDLE 2 #define STRIPE_SYNCING 3 #define STRIPE_INSYNC 4 #define STRIPE_PREREAD_ACTIVE 5 #define STRIPE_DELAYED 6 +#define STRIPE_DEGRADED 7 +#define STRIPE_BIT_DELAY 8 /* * Plugging: @@ -210,10 +212,20 @@ struct raid5_private_data { struct list_head handle_list; /* stripes needing handling */ struct list_head delayed_list; /* stripes that have plugged requests */ + struct list_head bitmap_list; /* stripes delaying awaiting bitmap update */ atomic_t preread_active_stripes; /* stripes with scheduled io */ char cache_name[20]; kmem_cache_t *slab_cache; /* for allocating stripes */ + + int seq_flush, seq_write; + int quiesce; + + int fullsync; /* set to 1 if a full sync is needed, + * (fresh device added). + * Cleared when a sync completes. + */ + /* * Free stripes pool */ -- GitLab From 934ce7c840992a771ffc478b132092db9c935c42 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:55 -0700 Subject: [PATCH 319/563] [PATCH] md: write-intent bitmap support for raid6 This is a direct port of the raid5 patch. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 2 +- drivers/md/raid6main.c | 133 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 124 insertions(+), 11 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index dbf540a7fccca..008149e2bc4a2 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -645,7 +645,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) if (sb->state & (1<<MD_SB_BITMAP_PRESENT) && mddev->bitmap_file == NULL) { - if (mddev->level != 1 && mddev->level != 5) { + if (mddev->level != 1 && mddev->level != 5 && mddev->level != 6) { /* FIXME use a better test */ printk(KERN_WARNING "md: bitmaps only support for raid1\n"); return -EINVAL; diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 09cb7272c09f9..267eb1430c834 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -29,6 +29,8 @@ #include <asm/atomic.h> #include "raid6.h" +#include <linux/raid/bitmap.h> + /* * Stripe cache */ @@ -98,8 +100,13 @@ static inline void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh) if (test_bit(STRIPE_HANDLE, &sh->state)) { if (test_bit(STRIPE_DELAYED, &sh->state)) list_add_tail(&sh->lru, &conf->delayed_list); - else + else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && + conf->seq_write == sh->bm_seq) + list_add_tail(&sh->lru, &conf->bitmap_list); + else { + clear_bit(STRIPE_BIT_DELAY, &sh->state); list_add_tail(&sh->lru, &conf->handle_list); + } md_wakeup_thread(conf->mddev->thread); } else { if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { @@ -262,6 +269,9 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector spin_lock_irq(&conf->device_lock); do { + wait_event_lock_irq(conf->wait_for_stripe, + conf->quiesce == 0, + conf->device_lock, /* nothing */); sh = __find_stripe(conf, sector); if (!sh) { if (!conf->inactive_blocked) @@ -906,6 +916,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in { struct bio **bip; raid6_conf_t *conf = sh->raid_conf; + int firstwrite=0; PRINTK("adding bh b#%llu to stripe s#%llu\n", (unsigned long long)bi->bi_sector, @@ -914,9 +925,11 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in spin_lock(&sh->lock); spin_lock_irq(&conf->device_lock); - if (forwrite) + if (forwrite) { bip = &sh->dev[dd_idx].towrite; - else + if (*bip == NULL && sh->dev[dd_idx].written == NULL) + firstwrite = 1; + } else bip = &sh->dev[dd_idx].toread; while (*bip && (*bip)->bi_sector < bi->bi_sector) { if ((*bip)->bi_sector + ((*bip)->bi_size >> 9) > bi->bi_sector) @@ -939,6 +952,13 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in (unsigned long long)bi->bi_sector, (unsigned long long)sh->sector, dd_idx); + if (conf->mddev->bitmap && firstwrite) { + sh->bm_seq = conf->seq_write; + bitmap_startwrite(conf->mddev->bitmap, sh->sector, + STRIPE_SECTORS, 0); + set_bit(STRIPE_BIT_DELAY, &sh->state); + } + if (forwrite) { /* check if page is covered */ sector_t sector = sh->dev[dd_idx].sector; @@ -1066,12 +1086,13 @@ static void handle_stripe(struct stripe_head *sh) * need to be failed */ if (failed > 2 && to_read+to_write+written) { - spin_lock_irq(&conf->device_lock); for (i=disks; i--; ) { + int bitmap_end = 0; + spin_lock_irq(&conf->device_lock); /* fail all writes first */ bi = sh->dev[i].towrite; sh->dev[i].towrite = NULL; - if (bi) to_write--; + if (bi) { to_write--; bitmap_end = 1; } if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) wake_up(&conf->wait_for_overlap); @@ -1089,6 +1110,7 @@ static void handle_stripe(struct stripe_head *sh) /* and fail all 'written' */ bi = sh->dev[i].written; sh->dev[i].written = NULL; + if (bi) bitmap_end = 1; while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); clear_bit(BIO_UPTODATE, &bi->bi_flags); @@ -1117,8 +1139,11 @@ static void handle_stripe(struct stripe_head *sh) bi = nextbi; } } + spin_unlock_irq(&conf->device_lock); + if (bitmap_end) + bitmap_endwrite(conf->mddev->bitmap, sh->sector, + STRIPE_SECTORS, 0, 0); } - spin_unlock_irq(&conf->device_lock); } if (failed > 2 && syncing) { md_done_sync(conf->mddev, STRIPE_SECTORS,0); @@ -1155,6 +1180,7 @@ static void handle_stripe(struct stripe_head *sh) if (!test_bit(R5_LOCKED, &dev->flags) && test_bit(R5_UPTODATE, &dev->flags) ) { /* We can return any write requests */ + int bitmap_end = 0; struct bio *wbi, *wbi2; PRINTK("Return write for stripe %llu disc %d\n", (unsigned long long)sh->sector, i); @@ -1170,7 +1196,13 @@ static void handle_stripe(struct stripe_head *sh) } wbi = wbi2; } + if (dev->towrite == NULL) + bitmap_end = 1; spin_unlock_irq(&conf->device_lock); + if (bitmap_end) + bitmap_endwrite(conf->mddev->bitmap, sh->sector, + STRIPE_SECTORS, + !test_bit(STRIPE_DEGRADED, &sh->state), 0); } } } @@ -1285,7 +1317,8 @@ static void handle_stripe(struct stripe_head *sh) } } /* now if nothing is locked, and if we have enough data, we can start a write request */ - if (locked == 0 && rcw == 0) { + if (locked == 0 && rcw == 0 && + !test_bit(STRIPE_BIT_DELAY, &sh->state)) { if ( must_compute > 0 ) { /* We have failed blocks and need to compute them */ switch ( failed ) { @@ -1388,6 +1421,7 @@ static void handle_stripe(struct stripe_head *sh) bdev = &sh->dev[failed_num[1]]; locked += !test_bit(R5_LOCKED, &bdev->flags); set_bit(R5_LOCKED, &bdev->flags); + clear_bit(STRIPE_DEGRADED, &sh->state); set_bit(R5_Wantwrite, &bdev->flags); set_bit(STRIPE_INSYNC, &sh->state); @@ -1457,6 +1491,8 @@ static void handle_stripe(struct stripe_head *sh) bi->bi_next = NULL; generic_make_request(bi); } else { + if (rw == 1) + set_bit(STRIPE_DEGRADED, &sh->state); PRINTK("skip op %ld on disc %d for sector %llu\n", bi->bi_rw, i, (unsigned long long)sh->sector); clear_bit(R5_LOCKED, &sh->dev[i].flags); @@ -1481,6 +1517,20 @@ static inline void raid6_activate_delayed(raid6_conf_t *conf) } } +static inline void activate_bit_delay(raid6_conf_t *conf) +{ + /* device_lock is held */ + struct list_head head; + list_add(&head, &conf->bitmap_list); + list_del_init(&conf->bitmap_list); + while (!list_empty(&head)) { + struct stripe_head *sh = list_entry(head.next, struct stripe_head, lru); + list_del_init(&sh->lru); + atomic_inc(&sh->count); + __release_stripe(conf, sh); + } +} + static void unplug_slaves(mddev_t *mddev) { raid6_conf_t *conf = mddev_to_conf(mddev); @@ -1513,8 +1563,10 @@ static void raid6_unplug_device(request_queue_t *q) spin_lock_irqsave(&conf->device_lock, flags); - if (blk_remove_plug(q)) + if (blk_remove_plug(q)) { + conf->seq_flush++; raid6_activate_delayed(conf); + } md_wakeup_thread(mddev->thread); spin_unlock_irqrestore(&conf->device_lock, flags); @@ -1652,10 +1704,20 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i sector_t first_sector; int raid_disks = conf->raid_disks; int data_disks = raid_disks - 2; + sector_t max_sector = mddev->size << 1; + int sync_blocks; - if (sector_nr >= mddev->size <<1) { + if (sector_nr >= max_sector) { /* just being told to finish up .. nothing much to do */ unplug_slaves(mddev); + + if (mddev->curr_resync < max_sector) /* aborted */ + bitmap_end_sync(mddev->bitmap, mddev->curr_resync, + &sync_blocks, 1); + else /* compelted sync */ + conf->fullsync = 0; + bitmap_close_sync(mddev->bitmap); + return 0; } /* if there are 2 or more failed drives and we are trying @@ -1667,6 +1729,13 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i *skipped = 1; return rv; } + if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) && + !conf->fullsync && sync_blocks >= STRIPE_SECTORS) { + /* we can skip this block, and probably more */ + sync_blocks /= STRIPE_SECTORS; + *skipped = 1; + return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */ + } x = sector_nr; chunk_offset = sector_div(x, sectors_per_chunk); @@ -1684,6 +1753,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } + bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 0); spin_lock(&sh->lock); set_bit(STRIPE_SYNCING, &sh->state); clear_bit(STRIPE_INSYNC, &sh->state); @@ -1717,6 +1787,13 @@ static void raid6d (mddev_t *mddev) while (1) { struct list_head *first; + if (conf->seq_flush - conf->seq_write > 0) { + int seq = conf->seq_flush; + bitmap_unplug(mddev->bitmap); + conf->seq_write = seq; + activate_bit_delay(conf); + } + if (list_empty(&conf->handle_list) && atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD && !blk_queue_plugged(mddev->queue) && @@ -1750,7 +1827,7 @@ static void raid6d (mddev_t *mddev) PRINTK("--- raid6d inactive\n"); } -static int run (mddev_t *mddev) +static int run(mddev_t *mddev) { raid6_conf_t *conf; int raid_disk, memory; @@ -1780,6 +1857,7 @@ static int run (mddev_t *mddev) init_waitqueue_head(&conf->wait_for_overlap); INIT_LIST_HEAD(&conf->handle_list); INIT_LIST_HEAD(&conf->delayed_list); + INIT_LIST_HEAD(&conf->bitmap_list); INIT_LIST_HEAD(&conf->inactive_list); atomic_set(&conf->active_stripes, 0); atomic_set(&conf->preread_active_stripes, 0); @@ -1899,6 +1977,9 @@ static int run (mddev_t *mddev) /* Ok, everything is just fine now */ mddev->array_size = mddev->size * (mddev->raid_disks - 2); + if (mddev->bitmap) + mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ; + mddev->queue->unplug_fn = raid6_unplug_device; mddev->queue->issue_flush_fn = raid6_issue_flush; return 0; @@ -2076,6 +2157,8 @@ static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) rdev->in_sync = 0; rdev->raid_disk = disk; found = 1; + if (rdev->saved_raid_disk != disk) + conf->fullsync = 1; p->rdev = rdev; break; } @@ -2105,6 +2188,35 @@ static int raid6_resize(mddev_t *mddev, sector_t sectors) return 0; } +static void raid6_quiesce(mddev_t *mddev, int state) +{ + raid6_conf_t *conf = mddev_to_conf(mddev); + + switch(state) { + case 1: /* stop all writes */ + spin_lock_irq(&conf->device_lock); + conf->quiesce = 1; + wait_event_lock_irq(conf->wait_for_stripe, + atomic_read(&conf->active_stripes) == 0, + conf->device_lock, /* nothing */); + spin_unlock_irq(&conf->device_lock); + break; + + case 0: /* re-enable writes */ + spin_lock_irq(&conf->device_lock); + conf->quiesce = 0; + wake_up(&conf->wait_for_stripe); + spin_unlock_irq(&conf->device_lock); + break; + } + if (mddev->thread) { + if (mddev->bitmap) + mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ; + else + mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; + md_wakeup_thread(mddev->thread); + } +} static mdk_personality_t raid6_personality= { .name = "raid6", @@ -2119,6 +2231,7 @@ static mdk_personality_t raid6_personality= .spare_active = raid6_spare_active, .sync_request = sync_request, .resize = raid6_resize, + .quiesce = raid6_quiesce, }; static int __init raid6_init (void) -- GitLab From a6fb0934f923f889055152cb0b033674f627460b Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:56 -0700 Subject: [PATCH 320/563] [PATCH] md: use kthread infrastructure in md Switch MD to use the kthread infrastructure, to simplify the code and get rid of tasklist_lock abuse in md_unregister_thread. Also don't flush signals in md_thread, as the called thread will always do that. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 48 ++++++++++-------------------------------------- 1 file changed, 10 insertions(+), 38 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 008149e2bc4a2..30e3624f3d905 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -34,6 +34,7 @@ #include <linux/module.h> #include <linux/config.h> +#include <linux/kthread.h> #include <linux/linkage.h> #include <linux/raid/md.h> #include <linux/raid/bitmap.h> @@ -3049,18 +3050,6 @@ static int md_thread(void * arg) { mdk_thread_t *thread = arg; - lock_kernel(); - - /* - * Detach thread - */ - - daemonize(thread->name, mdname(thread->mddev)); - - current->exit_signal = SIGCHLD; - allow_signal(SIGKILL); - thread->tsk = current; - /* * md_thread is a 'system-thread', it's priority should be very * high. We avoid resource deadlocks individually in each @@ -3072,14 +3061,14 @@ static int md_thread(void * arg) * bdflush, otherwise bdflush will deadlock if there are too * many dirty RAID5 blocks. */ - unlock_kernel(); complete(thread->event); - while (thread->run) { + while (!kthread_should_stop()) { void (*run)(mddev_t *); wait_event_interruptible_timeout(thread->wqueue, - test_bit(THREAD_WAKEUP, &thread->flags), + test_bit(THREAD_WAKEUP, &thread->flags) + || kthread_should_stop(), thread->timeout); try_to_freeze(); @@ -3088,11 +3077,8 @@ static int md_thread(void * arg) run = thread->run; if (run) run(thread->mddev); - - if (signal_pending(current)) - flush_signals(current); } - complete(thread->event); + return 0; } @@ -3109,11 +3095,9 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev, const char *name) { mdk_thread_t *thread; - int ret; struct completion event; - thread = (mdk_thread_t *) kmalloc - (sizeof(mdk_thread_t), GFP_KERNEL); + thread = kmalloc(sizeof(mdk_thread_t), GFP_KERNEL); if (!thread) return NULL; @@ -3126,8 +3110,8 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev, thread->mddev = mddev; thread->name = name; thread->timeout = MAX_SCHEDULE_TIMEOUT; - ret = kernel_thread(md_thread, thread, 0); - if (ret < 0) { + thread->tsk = kthread_run(md_thread, thread, mdname(thread->mddev)); + if (IS_ERR(thread->tsk)) { kfree(thread); return NULL; } @@ -3137,21 +3121,9 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev, void md_unregister_thread(mdk_thread_t *thread) { - struct completion event; - - init_completion(&event); - - thread->event = &event; - - /* As soon as ->run is set to NULL, the task could disappear, - * so we need to hold tasklist_lock until we have sent the signal - */ dprintk("interrupting MD-thread pid %d\n", thread->tsk->pid); - read_lock(&tasklist_lock); - thread->run = NULL; - send_sig(SIGKILL, thread->tsk, 1); - read_unlock(&tasklist_lock); - wait_for_completion(&event); + + kthread_stop(thread->tsk); kfree(thread); } -- GitLab From 9ba00538ada7ecb4fb8bd71ba734a8eada987817 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:57 -0700 Subject: [PATCH 321/563] [PATCH] md: ensure bitmap_writeback_daemon handles shutdown properly. mddev->bitmap gets clearred before the writeback daemon is stopped. So the write_back daemon needs to be careful not to dereference the 'bitmap' if it is NULL. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/bitmap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 90fe70d76a316..87145faac491a 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1156,6 +1156,9 @@ static void bitmap_writeback_daemon(mddev_t *mddev) err = -EINTR; goto out; } + if (bitmap == NULL) + /* about to be stopped. */ + return; PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap)); /* wait on bitmap page writebacks */ -- GitLab From 500af87abb81098da47474c81f29ea315a056dc5 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@cse.unsw.edu.au> Date: Fri, 9 Sep 2005 16:23:58 -0700 Subject: [PATCH 322/563] [PATCH] md: tidy up daemon stop/start code in md/bitmap.c The bitmap code used to have two daemons, so there is some 'common' start/stop code. But now there is only one, so the common code is just noise. This patch tidies this up somewhat. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/bitmap.c | 73 +++++++++++++++++---------------------------- drivers/md/raid1.c | 2 +- 2 files changed, 28 insertions(+), 47 deletions(-) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 87145faac491a..2fba2bbe72d8f 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -626,7 +626,7 @@ static void bitmap_file_unmap(struct bitmap *bitmap) page_cache_release(sb_page); } -static void bitmap_stop_daemons(struct bitmap *bitmap); +static void bitmap_stop_daemon(struct bitmap *bitmap); /* dequeue the next item in a page list -- don't call from irq context */ static struct page_list *dequeue_page(struct bitmap *bitmap) @@ -668,7 +668,7 @@ static void bitmap_file_put(struct bitmap *bitmap) bitmap->file = NULL; spin_unlock_irqrestore(&bitmap->lock, flags); - bitmap_stop_daemons(bitmap); + bitmap_stop_daemon(bitmap); drain_write_queues(bitmap); @@ -1188,21 +1188,12 @@ static void bitmap_writeback_daemon(mddev_t *mddev) } } -static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr, +static mdk_thread_t *bitmap_start_daemon(struct bitmap *bitmap, void (*func)(mddev_t *), char *name) { mdk_thread_t *daemon; - unsigned long flags; char namebuf[32]; - spin_lock_irqsave(&bitmap->lock, flags); - *ptr = NULL; - - if (!bitmap->file) /* no need for daemon if there's no backing file */ - goto out_unlock; - - spin_unlock_irqrestore(&bitmap->lock, flags); - #ifdef INJECT_FATAL_FAULT_2 daemon = NULL; #else @@ -1212,47 +1203,32 @@ static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr, if (!daemon) { printk(KERN_ERR "%s: failed to start bitmap daemon\n", bmname(bitmap)); - return -ECHILD; + return ERR_PTR(-ECHILD); } - spin_lock_irqsave(&bitmap->lock, flags); - *ptr = daemon; - md_wakeup_thread(daemon); /* start it running */ PRINTK("%s: %s daemon (pid %d) started...\n", bmname(bitmap), name, daemon->tsk->pid); -out_unlock: - spin_unlock_irqrestore(&bitmap->lock, flags); - return 0; -} -static int bitmap_start_daemons(struct bitmap *bitmap) -{ - int err = bitmap_start_daemon(bitmap, &bitmap->writeback_daemon, - bitmap_writeback_daemon, "bitmap_wb"); - return err; + return daemon; } -static void bitmap_stop_daemon(struct bitmap *bitmap, mdk_thread_t **ptr) +static void bitmap_stop_daemon(struct bitmap *bitmap) { - mdk_thread_t *daemon; - unsigned long flags; - - spin_lock_irqsave(&bitmap->lock, flags); - daemon = *ptr; - *ptr = NULL; - spin_unlock_irqrestore(&bitmap->lock, flags); - if (daemon) - md_unregister_thread(daemon); /* destroy the thread */ -} + /* the daemon can't stop itself... it'll just exit instead... */ + if (bitmap->writeback_daemon && ! IS_ERR(bitmap->writeback_daemon) && + current->pid != bitmap->writeback_daemon->tsk->pid) { + mdk_thread_t *daemon; + unsigned long flags; -static void bitmap_stop_daemons(struct bitmap *bitmap) -{ - /* the daemons can't stop themselves... they'll just exit instead... */ - if (bitmap->writeback_daemon && - current->pid != bitmap->writeback_daemon->tsk->pid) - bitmap_stop_daemon(bitmap, &bitmap->writeback_daemon); + spin_lock_irqsave(&bitmap->lock, flags); + daemon = bitmap->writeback_daemon; + bitmap->writeback_daemon = NULL; + spin_unlock_irqrestore(&bitmap->lock, flags); + if (daemon && ! IS_ERR(daemon)) + md_unregister_thread(daemon); /* destroy the thread */ + } } static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, @@ -1637,10 +1613,15 @@ int bitmap_create(mddev_t *mddev) mddev->bitmap = bitmap; - /* kick off the bitmap daemons */ - err = bitmap_start_daemons(bitmap); - if (err) - return err; + if (file) + /* kick off the bitmap writeback daemon */ + bitmap->writeback_daemon = + bitmap_start_daemon(bitmap, + bitmap_writeback_daemon, + "bitmap_wb"); + + if (IS_ERR(bitmap->writeback_daemon)) + return PTR_ERR(bitmap->writeback_daemon); return bitmap_update_sb(bitmap); error: diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index bfe78571586b9..a93ca478142a2 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1703,7 +1703,7 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks) return 0; } -void raid1_quiesce(mddev_t *mddev, int state) +static void raid1_quiesce(mddev_t *mddev, int state) { conf_t *conf = mddev_to_conf(mddev); -- GitLab From 53e87fbb5dc887766229eef3ba8bd8ab8853b066 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@suse.de> Date: Fri, 9 Sep 2005 16:23:58 -0700 Subject: [PATCH 323/563] [PATCH] md: choose better default offset for bitmap. On reflection, a better default location for hot-adding bitmaps with version-1 superblocks is immediately after the superblock. There might not be much room there, but there is usually atleast 3k, and that is a good start. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 30e3624f3d905..fd66c39589420 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -957,8 +957,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->events = le64_to_cpu(sb->events); mddev->bitmap_offset = 0; mddev->default_bitmap_offset = 0; - if (mddev->minor_version == 0) - mddev->default_bitmap_offset = -(64*1024)/512; + mddev->default_bitmap_offset = 1024; mddev->recovery_cp = le64_to_cpu(sb->resync_offset); memcpy(mddev->uuid, sb->set_uuid, 16); -- GitLab From 720a3dc39b030e273bc955641f2517874fd38fc5 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@suse.de> Date: Fri, 9 Sep 2005 16:23:59 -0700 Subject: [PATCH 324/563] [PATCH] md: use queue_hardsect_size instead of block_size for md superblock size calc. Doh. I want the physical hard-sector-size, not the current block size... Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index fd66c39589420..39b917bc0fc0b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -898,7 +898,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) rdev->data_offset = le64_to_cpu(sb->data_offset); rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256; - bmask = block_size(rdev->bdev)-1; + bmask = queue_hardsect_size(rdev->bdev->bd_disk->queue)-1; if (rdev->sb_size & bmask) rdev-> sb_size = (rdev->sb_size | bmask)+1; -- GitLab From 1cd6bf19bbe8098153d7a478d8fc551edbea9305 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@suse.de> Date: Fri, 9 Sep 2005 16:24:00 -0700 Subject: [PATCH 325/563] [PATCH] md: add information about superblock version to /proc/mdstat Leave it unchanged if the original (0.90) is used, incase it might be a compatability problem. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 39b917bc0fc0b..0a13016829da2 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3346,6 +3346,15 @@ static int md_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "\n %llu blocks", (unsigned long long)size); } + if (mddev->persistent) { + if (mddev->major_version != 0 || + mddev->minor_version != 90) { + seq_printf(seq," super %d.%d", + mddev->major_version, + mddev->minor_version); + } + } else + seq_printf(seq, " super non-persistent"); if (mddev->pers) { mddev->pers->status (seq, mddev); -- GitLab From b325a32e5732d7aef70ca3c58acb3953ed20f66c Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@suse.de> Date: Fri, 9 Sep 2005 16:24:00 -0700 Subject: [PATCH 326/563] [PATCH] md: report spare drives in /proc/mdstat Just like failed drives have (F), so spare drives now have (S). Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 0a13016829da2..f27e8f644dfe2 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3334,7 +3334,8 @@ static int md_seq_show(struct seq_file *seq, void *v) if (rdev->faulty) { seq_printf(seq, "(F)"); continue; - } + } else if (rdev->raid_disk < 0) + seq_printf(seq, "(S)"); /* spare */ size += rdev->size; } -- GitLab From 188c18fd7982d220f4dea234cbb5cc6c75d0f512 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@suse.de> Date: Fri, 9 Sep 2005 16:24:01 -0700 Subject: [PATCH 327/563] [PATCH] md: make sure the new 'sb_size' is set properly device added without pre-existing superblock. There are two ways to add devices to an md/raid array. It can have superblock written to it, and then given to the md driver, which will read the superblock (the new way) or md can be told (through SET_ARRAY_INFO) the shape of the array, and the told about individual drives, and md will create the required superblock (the old way). The newly introduced sb_size was only set for drives being added the new way, not the old ways. Oops :-( Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index f27e8f644dfe2..8c1f7954882aa 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2303,6 +2303,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) else rdev->in_sync = 0; + rdev->sb_size = MD_SB_BYTES; + if (info->state & (1<<MD_DISK_WRITEMOSTLY)) set_bit(WriteMostly, &rdev->flags); -- GitLab From 611815651b2640449bda928079160b9263efac1c Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@suse.de> Date: Fri, 9 Sep 2005 16:24:02 -0700 Subject: [PATCH 328/563] [PATCH] md: really get sb_size setting right in all cases There was another case where sb_size wasn't being set, so instead do the sensible thing and set if when filling in the content of a superblock. That ensures that whenever we write a superblock, the sb_size MUST be set. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/md.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 8c1f7954882aa..1554b924fbb9d 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -712,6 +712,8 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) int i; int active=0, working=0,failed=0,spare=0,nr_disks=0; + rdev->sb_size = MD_SB_BYTES; + sb = (mdp_super_t*)page_address(rdev->sb_page); memset(sb, 0, sizeof(*sb)); @@ -2303,8 +2305,6 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) else rdev->in_sync = 0; - rdev->sb_size = MD_SB_BYTES; - if (info->state & (1<<MD_DISK_WRITEMOSTLY)) set_bit(WriteMostly, &rdev->flags); -- GitLab From 6d508242b231cb6e6803faaef54456abe846edb8 Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@suse.de> Date: Fri, 9 Sep 2005 16:24:03 -0700 Subject: [PATCH 329/563] [PATCH] md: fix raid10 assembly when too many devices are missing If you try to assemble an array with too many missing devices, raid10 will now reject the attempt, instead of allowing it. Also check when hot-adding a drive and refuse the hot-add if the array is beyond hope. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/raid10.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 5e0b333793d5b..834bf0f862225 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -906,6 +906,27 @@ static void close_sync(conf_t *conf) conf->r10buf_pool = NULL; } +/* check if there are enough drives for + * every block to appear on atleast one + */ +static int enough(conf_t *conf) +{ + int first = 0; + + do { + int n = conf->copies; + int cnt = 0; + while (n--) { + if (conf->mirrors[first].rdev) + cnt++; + first = (first+1) % conf->raid_disks; + } + if (cnt == 0) + return 0; + } while (first != 0); + return 1; +} + static int raid10_spare_active(mddev_t *mddev) { int i; @@ -944,6 +965,8 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) * very different from resync */ return 0; + if (!enough(conf)) + return 0; for (mirror=0; mirror < mddev->raid_disks; mirror++) if ( !(p=conf->mirrors+mirror)->rdev) { @@ -1684,9 +1707,10 @@ static int run(mddev_t *mddev) init_waitqueue_head(&conf->wait_idle); init_waitqueue_head(&conf->wait_resume); - if (!conf->working_disks) { - printk(KERN_ERR "raid10: no operational mirrors for %s\n", - mdname(mddev)); + /* need to check that every block has at least one working mirror */ + if (!enough(conf)) { + printk(KERN_ERR "raid10: not enough operational mirrors for %s\n", + mdname(mddev)); goto out_free_conf; } -- GitLab From 87fc767b832ef5a681a0ff9d203c3289bc3be2bf Mon Sep 17 00:00:00 2001 From: NeilBrown <neilb@suse.de> Date: Fri, 9 Sep 2005 16:24:04 -0700 Subject: [PATCH 330/563] [PATCH] md: fix BUG when raid10 rebuilds without enough drives This shouldn't be a BUG. We should cope. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/md/raid10.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 834bf0f862225..5bd1e9ec899d8 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1474,7 +1474,13 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i } } if (j == conf->copies) { - BUG(); + /* Cannot recover, so abort the recovery */ + put_buf(r10_bio); + r10_bio = rb2; + if (!test_and_set_bit(MD_RECOVERY_ERR, &mddev->recovery)) + printk(KERN_INFO "raid10: %s: insufficient working devices for recovery.\n", + mdname(mddev)); + break; } } if (biolist == NULL) { -- GitLab From 354ba39cf96e439149541acf3c6c7c0df0a3ef25 Mon Sep 17 00:00:00 2001 From: John Kingman <kingman@storagegear.com> Date: Fri, 9 Sep 2005 18:23:32 -0700 Subject: [PATCH 331/563] [PATCH] IB CM: support CM redir Changes to CM to support CM and port redirection (REJ reason 24). Signed-off-by: John Kingman <kingman <at> storagegear.com> Signed-off-by: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/core/cm.c | 4 +++- include/rdma/ib_cm.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 4de93ba274a61..96136543aa4ed 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -173,7 +173,8 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv, if (IS_ERR(ah)) return PTR_ERR(ah); - m = ib_create_send_mad(mad_agent, 1, cm_id_priv->av.pkey_index, + m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, + cm_id_priv->av.pkey_index, ah, 0, sizeof(struct ib_mad_hdr), sizeof(struct ib_mad)-sizeof(struct ib_mad_hdr), GFP_ATOMIC); @@ -536,6 +537,7 @@ struct ib_cm_id *ib_create_cm_id(ib_cm_handler cm_handler, cm_id_priv->id.state = IB_CM_IDLE; cm_id_priv->id.cm_handler = cm_handler; cm_id_priv->id.context = context; + cm_id_priv->id.remote_cm_qpn = 1; ret = cm_alloc_id(cm_id_priv); if (ret) goto error; diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 77fe9039209b1..5308683c8c41a 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -290,6 +290,7 @@ struct ib_cm_id { enum ib_cm_lap_state lap_state; /* internal CM/debug use */ __be32 local_id; __be32 remote_id; + u32 remote_cm_qpn; /* 1 unless redirected */ }; /** -- GitLab From 9928890c1f94da58bf753ede937b7324f6832866 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Date: Sat, 10 Sep 2005 11:26:34 +0900 Subject: [PATCH 332/563] [IPV6]: rearrange constants for new advanced API to solve conflicts. 64, 65 are already used in ip6_tables. Pointed out by Patrick McHardy <kaber@trash.net>. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> --- include/linux/in6.h | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/include/linux/in6.h b/include/linux/in6.h index bd32b79d6295f..50cdc3ad61a7f 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -198,27 +198,29 @@ struct in6_flowlabel_req * MCAST_MSFILTER 48 */ -/* RFC3542 advanced socket options (50-67) */ -#define IPV6_RECVPKTINFO 50 -#define IPV6_PKTINFO 51 -#if 0 -#define IPV6_RECVPATHMTU 52 -#define IPV6_PATHMTU 53 -#define IPV6_DONTFRAG 54 -#define IPV6_USE_MIN_MTU 55 -#endif -#define IPV6_RECVHOPOPTS 56 -#define IPV6_HOPOPTS 57 -#if 0 -#define IPV6_RECVRTHDRDSTOPTS 58 /* Unused, see net/ipv6/datagram.c */ +/* + * Advanced API (RFC3542) (1) + * + * Note: IPV6_RECVRTHDRDSTOPTS does not exist. see net/ipv6/datagram.c. + */ + +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 +#define IPV6_RECVHOPOPTS 53 +#define IPV6_HOPOPTS 54 +#define IPV6_RTHDRDSTOPTS 55 +#define IPV6_RECVRTHDR 56 +#define IPV6_RTHDR 57 +#define IPV6_RECVDSTOPTS 58 +#define IPV6_DSTOPTS 59 +#if 0 /* not yet */ +#define IPV6_RECVPATHMTU 60 +#define IPV6_PATHMTU 61 +#define IPV6_DONTFRAG 62 +#define IPV6_USE_MIN_MTU 63 #endif -#define IPV6_RTHDRDSTOPTS 59 -#define IPV6_RECVRTHDR 60 -#define IPV6_RTHDR 61 -#define IPV6_RECVDSTOPTS 62 -#define IPV6_DSTOPTS 63 -#define IPV6_RECVHOPLIMIT 64 -#define IPV6_HOPLIMIT 65 #define IPV6_RECVTCLASS 66 #define IPV6_TCLASS 67 -- GitLab From dd27466df9924706ae34639ce3f4f837875d45c1 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Date: Sat, 10 Sep 2005 11:32:45 +0900 Subject: [PATCH 333/563] [IPV6]: Note values allocated for ip6_tables. To avoid future conflicts, add a note values allocated for ip6_tables. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> --- include/linux/in6.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/in6.h b/include/linux/in6.h index 50cdc3ad61a7f..304aaedea305d 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -221,6 +221,20 @@ struct in6_flowlabel_req #define IPV6_DONTFRAG 62 #define IPV6_USE_MIN_MTU 63 #endif + +/* + * Netfilter + * + * Following socket options are used in ip6_tables; + * see include/linux/netfilter_ipv6/ip6_tables.h. + * + * IP6T_SO_SET_REPLACE / IP6T_SO_GET_INFO 64 + * IP6T_SO_SET_ADD_COUNTERS / IP6T_SO_GET_ENTRIES 65 + */ + +/* + * Advanced API (RFC3542) (2) + */ #define IPV6_RECVTCLASS 66 #define IPV6_TCLASS 67 -- GitLab From 1b205c2d2464bfecbba80227e74b412596dc5521 Mon Sep 17 00:00:00 2001 From: Roland Dreier <roland@eddore.topspincom.com> Date: Fri, 9 Sep 2005 20:52:00 -0700 Subject: [PATCH 334/563] [PATCH] IB: fix CM use-after-free If the CM REQ handling function gets to error2, then it frees cm_id_priv->timewait_info. But the next line goes through ib_destroy_cm_id() -> ib_send_cm_rej() -> cm_reset_to_idle(), which ends up calling cm_cleanup_timewait(), which dereferences the pointer we just freed. Make sure we clear cm_id_priv->timewait_info after freeing it, so that doesn't happen. Signed-off-by: Roland Dreier <rolandd@cisco.com> --- drivers/infiniband/core/cm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 96136543aa4ed..54db6d4831f1a 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -1315,6 +1315,7 @@ error3: atomic_dec(&cm_id_priv->refcount); cm_deref_id(listen_cm_id_priv); cm_cleanup_timewait(cm_id_priv->timewait_info); error2: kfree(cm_id_priv->timewait_info); + cm_id_priv->timewait_info = NULL; error1: ib_destroy_cm_id(&cm_id_priv->id); return ret; } -- GitLab From e6df439b89dbf9eb977c2dc6f7b0644be3704df4 Mon Sep 17 00:00:00 2001 From: Brian Haley <brian.haley@hp.com> Date: Sat, 10 Sep 2005 00:15:06 -0700 Subject: [PATCH 335/563] [IPV6]: Bring Type 0 routing header in-line with rfc3542. Signed-off-by: Brian Haley <brian.haley@hp.com> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net> --- include/linux/ipv6.h | 2 +- net/ipv6/exthdrs.c | 3 +-- net/ipv6/netfilter/ip6t_rt.c | 14 +++++++------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 6c5f7b39a4b01..bb6f88e14061e 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -68,7 +68,7 @@ struct ipv6_opt_hdr { struct rt0_hdr { struct ipv6_rt_hdr rt_hdr; - __u32 bitmap; /* strict/loose bit map */ + __u32 reserved; struct in6_addr addr[0]; #define rt0_type rt_hdr.type diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 47122728212ab..922549581abc2 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -406,8 +406,7 @@ ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr) memcpy(opt->srcrt, hdr, sizeof(*hdr)); irthdr = (struct rt0_hdr*)opt->srcrt; - /* Obsolete field, MBZ, when originated by us */ - irthdr->bitmap = 0; + irthdr->reserved = 0; opt->srcrt->segments_left = n; for (i=0; i<n; i++) memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16); diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index a9526b773d284..2bb670037df3a 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c @@ -161,8 +161,8 @@ match(const struct sk_buff *skb, ((rtinfo->hdrlen == hdrlen) ^ !!(rtinfo->invflags & IP6T_RT_INV_LEN)))); DEBUGP("res %02X %02X %02X ", - (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)rh)->bitmap, - !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)rh)->bitmap))); + (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)rh)->reserved, + !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)rh)->reserved))); ret = (rh != NULL) && @@ -179,12 +179,12 @@ match(const struct sk_buff *skb, !!(rtinfo->invflags & IP6T_RT_INV_TYP))); if (ret && (rtinfo->flags & IP6T_RT_RES)) { - u_int32_t *bp, _bitmap; - bp = skb_header_pointer(skb, - ptr + offsetof(struct rt0_hdr, bitmap), - sizeof(_bitmap), &_bitmap); + u_int32_t *rp, _reserved; + rp = skb_header_pointer(skb, + ptr + offsetof(struct rt0_hdr, reserved), + sizeof(_reserved), &_reserved); - ret = (*bp == 0); + ret = (*rp == 0); } DEBUGP("#%d ",rtinfo->addrnr); -- GitLab From c4a72cbdb39fd559988b16d118f7e5782935ff11 Mon Sep 17 00:00:00 2001 From: Russell King <rmk@dyn-67.arm.linux.org.uk> Date: Sat, 10 Sep 2005 11:58:21 +0100 Subject: [PATCH 336/563] [MMC] Add mmc_detect_change() delay support for wbsd driver Convert wbsd to use the new delay functionality in mmc_detect_change() rather than implementing its own timer. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- drivers/mmc/wbsd.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index a62c86fef5ccc..e11e55dc89249 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1111,20 +1111,6 @@ static void wbsd_reset_ignore(unsigned long data) spin_unlock_bh(&host->lock); } -/* - * Helper function for card detection - */ -static void wbsd_detect_card(unsigned long data) -{ - struct wbsd_host *host = (struct wbsd_host*)data; - - BUG_ON(host == NULL); - - DBG("Executing card detection\n"); - - mmc_detect_change(host->mmc, 0); -} - /* * Tasklets */ @@ -1169,14 +1155,16 @@ static void wbsd_tasklet_card(unsigned long param) DBG("Card inserted\n"); host->flags |= WBSD_FCARD_PRESENT; + spin_unlock(&host->lock); + /* * Delay card detection to allow electrical connections * to stabilise. */ - mod_timer(&host->detect_timer, jiffies + HZ/2); + mmc_detect_change(host->mmc, msecs_to_jiffies(500)); } - - spin_unlock(&host->lock); + else + spin_unlock(&host->lock); } else if (host->flags & WBSD_FCARD_PRESENT) { @@ -1409,10 +1397,6 @@ static int __devinit wbsd_alloc_mmc(struct device* dev) /* * Set up timers */ - init_timer(&host->detect_timer); - host->detect_timer.data = (unsigned long)host; - host->detect_timer.function = wbsd_detect_card; - init_timer(&host->ignore_timer); host->ignore_timer.data = (unsigned long)host; host->ignore_timer.function = wbsd_reset_ignore; @@ -1454,7 +1438,6 @@ static void __devexit wbsd_free_mmc(struct device* dev) BUG_ON(host == NULL); del_timer_sync(&host->ignore_timer); - del_timer_sync(&host->detect_timer); mmc_free_host(mmc); -- GitLab From 6d12884259ac65f74538b7819f5fadf4ebb0d569 Mon Sep 17 00:00:00 2001 From: Zach Brown <zach.brown@oracle.com> Date: Wed, 7 Sep 2005 12:08:23 -0700 Subject: [PATCH 337/563] [PATCH] kbuild: add kernelrelease to 'make help' Dunno if there was a conscious decision to leave it out, but if you're happy with adding some help text for it here's a patch against 2.6.13-mm1.. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 2402430c87e66..0d0576a622bfd 100644 --- a/Makefile +++ b/Makefile @@ -1053,6 +1053,7 @@ help: @echo ' rpm - Build a kernel as an RPM package' @echo ' tags/TAGS - Generate tags file for editors' @echo ' cscope - Generate cscope index' + @echo ' kernelrelease - Output the release version string' @echo '' @echo 'Static analysers' @echo ' buildcheck - List dangling references to vmlinux discarded sections' -- GitLab From 7b49bb9aff8b14d15da58111d8908c877c0a525e Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" <viro@ZenIV.linux.org.uk> Date: Fri, 9 Sep 2005 21:14:35 +0100 Subject: [PATCH 338/563] [PATCH] kbuild: CF=<arguments> passes arguments to sparse Allows to add to sparse arguments without mutilating makefiles - just pass CF=<arguments> and they will be added to CHECKFLAGS. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0d0576a622bfd..6a405882b1f7e 100644 --- a/Makefile +++ b/Makefile @@ -334,7 +334,7 @@ KALLSYMS = scripts/kallsyms PERL = perl CHECK = sparse -CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ +CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ $(CF) MODFLAGS = -DMODULE CFLAGS_MODULE = $(MODFLAGS) AFLAGS_MODULE = $(MODFLAGS) -- GitLab From 4e25d8bb9550fb5912165196fe8502cdb831a336 Mon Sep 17 00:00:00 2001 From: Jan Beulich <JBeulich@novell.com> Date: Thu, 8 Sep 2005 17:07:35 +0200 Subject: [PATCH 339/563] [PATCH] kbuild: adjust .version updating In order to maintain a more correct build number, updates to the version number should only be commited after a successful link of vmlinux, not before (so that errors in the link process don't lead to pointless increments). Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6a405882b1f7e..485a11a1985f9 100644 --- a/Makefile +++ b/Makefile @@ -641,8 +641,13 @@ quiet_cmd_vmlinux__ ?= LD $@ # Generate new vmlinux version quiet_cmd_vmlinux_version = GEN .version cmd_vmlinux_version = set -e; \ - . $(srctree)/scripts/mkversion > .tmp_version; \ - mv -f .tmp_version .version; \ + if [ ! -r .version ]; then \ + rm -f .version; \ + echo 1 >.version; \ + else \ + mv .version .old_version; \ + expr 0$$(cat .old_version) + 1 >.version; \ + fi; \ $(MAKE) $(build)=init # Generate System.map @@ -756,6 +761,7 @@ endif # ifdef CONFIG_KALLSYMS # vmlinux image - including updated kernel symbols vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE $(call if_changed_rule,vmlinux__) + $(Q)rm -f .old_version # The actual objects are generated when descending, # make sure no implicit rule kicks in -- GitLab From cd05e6bdc6001ac6e8ab13720693b7e1302d9848 Mon Sep 17 00:00:00 2001 From: Jan Beulich <JBeulich@novell.com> Date: Tue, 6 Sep 2005 11:47:04 +0200 Subject: [PATCH 340/563] [PATCH] kbuild: fix split-include dependency Splitting of autoconf.h requires that split-include was built before, and needs to be-re-done when split-include changes. This dependency was previously missing. Additionally, since autoconf.h is (suppoosed to be) generated as a side effect of executing config targets, include/linux should be created prior to running the respective sub-make. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- Makefile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 485a11a1985f9..524fb48fa334f 100644 --- a/Makefile +++ b/Makefile @@ -382,6 +382,9 @@ RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CV scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic +# To avoid any implicit rule to kick in, define an empty command. +scripts/basic/%: scripts_basic ; + .PHONY: outputmakefile # outputmakefile generate a Makefile to be placed in output directory, if # using a seperate output directory. This allows convinient use @@ -444,9 +447,8 @@ ifeq ($(config-targets),1) include $(srctree)/arch/$(ARCH)/Makefile export KBUILD_DEFCONFIG -config: scripts_basic outputmakefile FORCE - $(Q)$(MAKE) $(build)=scripts/kconfig $@ -%config: scripts_basic outputmakefile FORCE +config %config: scripts_basic outputmakefile FORCE + $(Q)mkdir -p include/linux $(Q)$(MAKE) $(build)=scripts/kconfig $@ else @@ -854,7 +856,7 @@ include/asm: # Split autoconf.h into include/linux/config/* -include/config/MARKER: include/linux/autoconf.h +include/config/MARKER: scripts/basic/split-include include/linux/autoconf.h @echo ' SPLIT include/linux/autoconf.h -> include/config/*' @scripts/basic/split-include include/linux/autoconf.h include/config @touch $@ -- GitLab From caba0233bc85ec311159a35f138d957d05cf2fe8 Mon Sep 17 00:00:00 2001 From: Roland McGrath <roland@redhat.com> Date: Sat, 3 Sep 2005 13:57:15 -0700 Subject: [PATCH 341/563] [PATCH] kbuild: ignore all debugging info sections in scripts/reference_discarded.pl GCC 4 emits more DWARF debugging information than before and there is now a .debug_loc section as well. This causes "make buildcheck" to fail. Rather than just add that one to the special case list, I used a regexp to ignore any .debug_ANYTHING sections in case more show up in the future. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- scripts/reference_discarded.pl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scripts/reference_discarded.pl b/scripts/reference_discarded.pl index f04f627368516..c2d54148a91f4 100644 --- a/scripts/reference_discarded.pl +++ b/scripts/reference_discarded.pl @@ -91,12 +91,7 @@ foreach $object (keys(%object)) { $from !~ /\.exit\.data$/ && $from !~ /\.altinstructions$/ && $from !~ /\.pdr$/ && - $from !~ /\.debug_info$/ && - $from !~ /\.debug_aranges$/ && - $from !~ /\.debug_ranges$/ && - $from !~ /\.debug_line$/ && - $from !~ /\.debug_frame$/ && - $from !~ /\.debug_loc$/ && + $from !~ /\.debug_.*$/ && $from !~ /\.exitcall\.exit$/ && $from !~ /\.eh_frame$/ && $from !~ /\.stab$/)) { -- GitLab From fe1e86049813641a518d15adf7191bd711b4f611 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov <dtor_core@ameritech.net> Date: Sat, 10 Sep 2005 12:03:38 -0500 Subject: [PATCH 342/563] Input: clean up whitespace and formatting in drivers/char/keyboard.c Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/char/keyboard.c | 109 ++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index b12d58ee532b6..449d029ad4f40 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -14,7 +14,7 @@ * `Sticky' modifier keys, 951006. * * 11-11-96: SAK should now work in the raw mode (Martin Mares) - * + * * Modified to provide 'generic' keyboard support by Hamish Macdonald * Merge with the m68k keyboard driver and split-off of the PC low-level * parts by Geert Uytterhoeven, May 1997 @@ -52,7 +52,7 @@ extern void ctrl_alt_del(void); /* * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. * This seems a good reason to start with NumLock off. On HIL keyboards - * of PARISC machines however there is no NumLock key and everyone expects the keypad + * of PARISC machines however there is no NumLock key and everyone expects the keypad * to be used for numbers. */ @@ -76,17 +76,17 @@ void compute_shiftstate(void); k_meta, k_ascii, k_lock, k_lowercase,\ k_slock, k_dead2, k_ignore, k_ignore -typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, +typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs); static k_handler_fn K_HANDLERS; static k_handler_fn *k_handler[16] = { K_HANDLERS }; #define FN_HANDLERS\ - fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ - fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ - fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ - fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ - fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num + fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ + fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ + fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ + fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ + fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num typedef void (fn_handler_fn)(struct vc_data *vc, struct pt_regs *regs); static fn_handler_fn FN_HANDLERS; @@ -159,13 +159,13 @@ static int sysrq_alt; */ int getkeycode(unsigned int scancode) { - struct list_head * node; + struct list_head *node; struct input_dev *dev = NULL; - list_for_each(node,&kbd_handler.h_list) { - struct input_handle * handle = to_handle_h(node); - if (handle->dev->keycodesize) { - dev = handle->dev; + list_for_each(node, &kbd_handler.h_list) { + struct input_handle *handle = to_handle_h(node); + if (handle->dev->keycodesize) { + dev = handle->dev; break; } } @@ -181,15 +181,15 @@ int getkeycode(unsigned int scancode) int setkeycode(unsigned int scancode, unsigned int keycode) { - struct list_head * node; + struct list_head *node; struct input_dev *dev = NULL; unsigned int i, oldkey; - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); - if (handle->dev->keycodesize) { - dev = handle->dev; - break; + if (handle->dev->keycodesize) { + dev = handle->dev; + break; } } @@ -216,11 +216,11 @@ int setkeycode(unsigned int scancode, unsigned int keycode) } /* - * Making beeps and bells. + * Making beeps and bells. */ static void kd_nosound(unsigned long ignored) { - struct list_head * node; + struct list_head *node; list_for_each(node,&kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); @@ -237,12 +237,12 @@ static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); void kd_mksound(unsigned int hz, unsigned int ticks) { - struct list_head * node; + struct list_head *node; del_timer(&kd_mksound_timer); if (hz) { - list_for_each_prev(node,&kbd_handler.h_list) { + list_for_each_prev(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) { @@ -337,19 +337,19 @@ static void to_utf8(struct vc_data *vc, ushort c) if (c < 0x80) /* 0******* */ put_queue(vc, c); - else if (c < 0x800) { + else if (c < 0x800) { /* 110***** 10****** */ - put_queue(vc, 0xc0 | (c >> 6)); + put_queue(vc, 0xc0 | (c >> 6)); put_queue(vc, 0x80 | (c & 0x3f)); - } else { + } else { /* 1110**** 10****** 10****** */ put_queue(vc, 0xe0 | (c >> 12)); put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); put_queue(vc, 0x80 | (c & 0x3f)); - } + } } -/* +/* * Called after returning from RAW mode or when changing consoles - recompute * shift_down[] and shift_state from key_down[] maybe called when keymap is * undefined, so that shiftkey release is seen @@ -360,7 +360,7 @@ void compute_shiftstate(void) shift_state = 0; memset(shift_down, 0, sizeof(shift_down)); - + for (i = 0; i < ARRAY_SIZE(key_down); i++) { if (!key_down[i]) @@ -499,9 +499,9 @@ static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs) if (want_console != -1) cur = want_console; - for (i = cur-1; i != cur; i--) { + for (i = cur - 1; i != cur; i--) { if (i == -1) - i = MAX_NR_CONSOLES-1; + i = MAX_NR_CONSOLES - 1; if (vc_cons_allocated(i)) break; } @@ -567,9 +567,9 @@ static void fn_compose(struct vc_data *vc, struct pt_regs *regs) static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs) { - if (spawnpid) - if(kill_proc(spawnpid, spawnsig, 1)) - spawnpid = 0; + if (spawnpid) + if (kill_proc(spawnpid, spawnsig, 1)) + spawnpid = 0; } static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) @@ -603,8 +603,8 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag, struct return; if (value >= ARRAY_SIZE(fn_handler)) return; - if ((kbd->kbdmode == VC_RAW || - kbd->kbdmode == VC_MEDIUMRAW) && + if ((kbd->kbdmode == VC_RAW || + kbd->kbdmode == VC_MEDIUMRAW) && value != KVAL(K_SAK)) return; /* SAK is allowed even in raw mode */ fn_handler[value](vc, regs); @@ -894,11 +894,11 @@ static inline unsigned char getleds(void) static void kbd_bh(unsigned long dummy) { - struct list_head * node; + struct list_head *node; unsigned char leds = getleds(); if (leds != ledstate) { - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle * handle = to_handle_h(node); input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); @@ -963,11 +963,11 @@ static int sparc_l1_a_state = 0; extern void sun_do_break(void); #endif -static int emulate_raw(struct vc_data *vc, unsigned int keycode, +static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { if (keycode > 255 || !x86_keycodes[keycode]) - return -1; + return -1; switch (keycode) { case KEY_PAUSE: @@ -981,7 +981,7 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, case KEY_HANJA: if (!up_flag) put_queue(vc, 0xf2); return 0; - } + } if (keycode == KEY_SYSRQ && sysrq_alt) { put_queue(vc, 0x54 | up_flag); @@ -1104,11 +1104,12 @@ static void kbd_keycode(unsigned int keycode, int down, else clear_bit(keycode, key_down); - if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || (tty && - (!L_ECHO(tty) && tty->driver->chars_in_buffer(tty))))) { + if (rep && + (!vc_kbd_mode(kbd, VC_REPEAT) || + (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) { /* * Don't repeat a key if the input buffers are not empty and the - * characters get aren't echoed locally. This makes key repeat + * characters get aren't echoed locally. This makes key repeat * usable with slow applications and under heavy loads. */ return; @@ -1130,7 +1131,8 @@ static void kbd_keycode(unsigned int keycode, int down, type = KTYP(keysym); if (type < 0xf0) { - if (down && !raw_mode) to_utf8(vc, keysym); + if (down && !raw_mode) + to_utf8(vc, keysym); return; } @@ -1154,7 +1156,7 @@ static void kbd_keycode(unsigned int keycode, int down, kbd->slockstate = 0; } -static void kbd_event(struct input_handle *handle, unsigned int event_type, +static void kbd_event(struct input_handle *handle, unsigned int event_type, unsigned int event_code, int value) { if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) @@ -1166,15 +1168,13 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, schedule_console_callback(); } -static char kbd_name[] = "kbd"; - /* * When a keyboard (or other input device) is found, the kbd_connect * function is called. The function then looks at the device, and if it * likes it, it can open it and get events from it. In this (kbd_connect) * function, we should decide which VT to bind that keyboard to initially. */ -static struct input_handle *kbd_connect(struct input_handler *handler, +static struct input_handle *kbd_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { @@ -1182,18 +1182,19 @@ static struct input_handle *kbd_connect(struct input_handler *handler, int i; for (i = KEY_RESERVED; i < BTN_MISC; i++) - if (test_bit(i, dev->keybit)) break; + if (test_bit(i, dev->keybit)) + break; - if ((i == BTN_MISC) && !test_bit(EV_SND, dev->evbit)) + if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) return NULL; - if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) return NULL; memset(handle, 0, sizeof(struct input_handle)); handle->dev = dev; handle->handler = handler; - handle->name = kbd_name; + handle->name = "kbd"; input_open_device(handle); kbd_refresh_leds(handle); @@ -1212,11 +1213,11 @@ static struct input_device_id kbd_ids[] = { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT(EV_KEY) }, }, - + { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT(EV_SND) }, - }, + }, { }, /* Terminating entry */ }; -- GitLab From d39969deee4b541be4ee5789a2e4c14511c886e2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov <dtor_core@ameritech.net> Date: Sat, 10 Sep 2005 12:04:42 -0500 Subject: [PATCH 343/563] Input: i8042 - use kzalloc instead of kcalloc Signed-off-by: Dmitry Torokhov <dtor@mail.ru> --- drivers/input/serio/i8042.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 19ef35db342ee..40d451ce07ffe 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -986,7 +986,7 @@ static int __init i8042_create_kbd_port(void) struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; - serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL); + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!serio) return -ENOMEM; @@ -1011,7 +1011,7 @@ static int __init i8042_create_aux_port(void) struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO]; - serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL); + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!serio) return -ENOMEM; @@ -1036,7 +1036,7 @@ static int __init i8042_create_mux_port(int index) struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index]; - serio = kcalloc(1, sizeof(struct serio), GFP_KERNEL); + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!serio) return -ENOMEM; -- GitLab From b4012a9895b3e28e3bff3aa534d58c7827af6d4f Mon Sep 17 00:00:00 2001 From: Andrew Morton <akpm@osdl.org> Date: Sat, 10 Sep 2005 00:25:47 -0700 Subject: [PATCH 344/563] [PATCH] ntfs build fix *** Warning: "bit_spin_lock" [fs/ntfs/ntfs.ko] undefined! *** Warning: "bit_spin_unlock" [fs/ntfs/ntfs.ko] undefined! Cc: Anton Altaparmakov <aia21@cantab.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/ntfs/aops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 545236414d592..b6cc8cf24626b 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -27,6 +27,7 @@ #include <linux/swap.h> #include <linux/buffer_head.h> #include <linux/writeback.h> +#include <linux/bit_spinlock.h> #include "aops.h" #include "attrib.h" -- GitLab From 4327edf6b8a7ac7dce144313947995538842d8fd Mon Sep 17 00:00:00 2001 From: Alan Cox <alan@lxorguk.ukuu.org.uk> Date: Sat, 10 Sep 2005 00:25:49 -0700 Subject: [PATCH 345/563] [PATCH] Subject: PATCH: fix numa caused compile warnings pcibus_to_cpumask expands into more than just an initialiser so gcc moans about code before variable declarations. Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/pci/pci-sysfs.c | 10 +++++++--- drivers/pci/probe.c | 6 ++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index cc9d65388e623..56a3b397efee2 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -44,10 +44,14 @@ pci_config_attr(subsystem_device, "0x%04x\n"); pci_config_attr(class, "0x%06x\n"); pci_config_attr(irq, "%u\n"); -static ssize_t local_cpus_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t local_cpus_show(struct device *dev, + struct device_attribute *attr, char *buf) { - cpumask_t mask = pcibus_to_cpumask(to_pci_dev(dev)->bus); - int len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask); + cpumask_t mask; + int len; + + mask = pcibus_to_cpumask(to_pci_dev(dev)->bus); + len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask); strcat(buf,"\n"); return 1+len; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 35caec13023a0..26a55d08b506a 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -72,11 +72,13 @@ void pci_remove_legacy_files(struct pci_bus *bus) { return; } /* * PCI Bus Class Devices */ -static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, char *buf) +static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, + char *buf) { - cpumask_t cpumask = pcibus_to_cpumask(to_pci_bus(class_dev)); int ret; + cpumask_t cpumask; + cpumask = pcibus_to_cpumask(to_pci_bus(class_dev)); ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask); if (ret < PAGE_SIZE) buf[ret++] = '\n'; -- GitLab From fb1c8f93d869b34cacb8b8932e2b83d96a19d720 Mon Sep 17 00:00:00 2001 From: Ingo Molnar <mingo@elte.hu> Date: Sat, 10 Sep 2005 00:25:56 -0700 Subject: [PATCH 346/563] [PATCH] spinlock consolidation This patch (written by me and also containing many suggestions of Arjan van de Ven) does a major cleanup of the spinlock code. It does the following things: - consolidates and enhances the spinlock/rwlock debugging code - simplifies the asm/spinlock.h files - encapsulates the raw spinlock type and moves generic spinlock features (such as ->break_lock) into the generic code. - cleans up the spinlock code hierarchy to get rid of the spaghetti. Most notably there's now only a single variant of the debugging code, located in lib/spinlock_debug.c. (previously we had one SMP debugging variant per architecture, plus a separate generic one for UP builds) Also, i've enhanced the rwlock debugging facility, it will now track write-owners. There is new spinlock-owner/CPU-tracking on SMP builds too. All locks have lockup detection now, which will work for both soft and hard spin/rwlock lockups. The arch-level include files now only contain the minimally necessary subset of the spinlock code - all the rest that can be generalized now lives in the generic headers: include/asm-i386/spinlock_types.h | 16 include/asm-x86_64/spinlock_types.h | 16 I have also split up the various spinlock variants into separate files, making it easier to see which does what. The new layout is: SMP | UP ----------------------------|----------------------------------- asm/spinlock_types_smp.h | linux/spinlock_types_up.h linux/spinlock_types.h | linux/spinlock_types.h asm/spinlock_smp.h | linux/spinlock_up.h linux/spinlock_api_smp.h | linux/spinlock_api_up.h linux/spinlock.h | linux/spinlock.h /* * here's the role of the various spinlock/rwlock related include files: * * on SMP builds: * * asm/spinlock_types.h: contains the raw_spinlock_t/raw_rwlock_t and the * initializers * * linux/spinlock_types.h: * defines the generic type and initializers * * asm/spinlock.h: contains the __raw_spin_*()/etc. lowlevel * implementations, mostly inline assembly code * * (also included on UP-debug builds:) * * linux/spinlock_api_smp.h: * contains the prototypes for the _spin_*() APIs. * * linux/spinlock.h: builds the final spin_*() APIs. * * on UP builds: * * linux/spinlock_type_up.h: * contains the generic, simplified UP spinlock type. * (which is an empty structure on non-debug builds) * * linux/spinlock_types.h: * defines the generic type and initializers * * linux/spinlock_up.h: * contains the __raw_spin_*()/etc. version of UP * builds. (which are NOPs on non-debug, non-preempt * builds) * * (included on UP-non-debug builds:) * * linux/spinlock_api_up.h: * builds the _spin_*() APIs. * * linux/spinlock.h: builds the final spin_*() APIs. */ All SMP and UP architectures are converted by this patch. arm, i386, ia64, ppc, ppc64, s390/s390x, x64 was build-tested via crosscompilers. m32r, mips, sh, sparc, have not been tested yet, but should be mostly fine. From: Grant Grundler <grundler@parisc-linux.org> Booted and lightly tested on a500-44 (64-bit, SMP kernel, dual CPU). Builds 32-bit SMP kernel (not booted or tested). I did not try to build non-SMP kernels. That should be trivial to fix up later if necessary. I converted bit ops atomic_hash lock to raw_spinlock_t. Doing so avoids some ugly nesting of linux/*.h and asm/*.h files. Those particular locks are well tested and contained entirely inside arch specific code. I do NOT expect any new issues to arise with them. If someone does ever need to use debug/metrics with them, then they will need to unravel this hairball between spinlocks, atomic ops, and bit ops that exist only because parisc has exactly one atomic instruction: LDCW (load and clear word). From: "Luck, Tony" <tony.luck@intel.com> ia64 fix Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Arjan van de Ven <arjanv@infradead.org> Signed-off-by: Grant Grundler <grundler@parisc-linux.org> Cc: Matthew Wilcox <willy@debian.org> Signed-off-by: Hirokazu Takata <takata@linux-m32r.org> Signed-off-by: Mikael Pettersson <mikpe@csd.uu.se> Signed-off-by: Benoit Boissinot <benoit.boissinot@ens-lyon.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/alpha/kernel/alpha_ksyms.c | 9 - arch/alpha/kernel/smp.c | 172 -------- arch/ia64/kernel/mca.c | 11 +- arch/m32r/kernel/smp.c | 48 +- arch/mips/lib/dec_and_lock.c | 8 - arch/parisc/lib/Makefile | 2 - arch/parisc/lib/bitops.c | 4 +- arch/parisc/lib/debuglocks.c | 277 ------------ arch/ppc/lib/Makefile | 1 - arch/ppc/lib/dec_and_lock.c | 8 - arch/ppc64/lib/dec_and_lock.c | 8 - arch/ppc64/lib/locks.c | 14 +- arch/s390/lib/spinlock.c | 12 +- arch/sparc/kernel/sparc_ksyms.c | 10 - arch/sparc/lib/Makefile | 2 - arch/sparc/lib/debuglocks.c | 202 --------- arch/sparc64/kernel/process.c | 5 - arch/sparc64/kernel/sparc64_ksyms.c | 5 - arch/sparc64/lib/Makefile | 1 - arch/sparc64/lib/debuglocks.c | 366 ---------------- fs/buffer.c | 1 + include/asm-alpha/spinlock.h | 96 ++-- include/asm-alpha/spinlock_types.h | 20 + include/asm-arm/spinlock.h | 50 +-- include/asm-arm/spinlock_types.h | 20 + include/asm-i386/spinlock.h | 200 +++------ include/asm-i386/spinlock_types.h | 20 + include/asm-ia64/spinlock.h | 69 ++- include/asm-ia64/spinlock_types.h | 21 + include/asm-m32r/spinlock.h | 127 ++---- include/asm-m32r/spinlock_types.h | 23 + include/asm-mips/spinlock.h | 75 ++-- include/asm-mips/spinlock_types.h | 20 + include/asm-parisc/atomic.h | 12 +- include/asm-parisc/bitops.h | 2 +- include/asm-parisc/cacheflush.h | 1 + include/asm-parisc/processor.h | 1 + include/asm-parisc/spinlock.h | 163 ++----- include/asm-parisc/spinlock_types.h | 21 + include/asm-parisc/system.h | 24 +- include/asm-ppc/spinlock.h | 91 +--- include/asm-ppc/spinlock_types.h | 20 + include/asm-ppc64/spinlock.h | 191 ++++---- include/asm-ppc64/spinlock_types.h | 20 + include/asm-s390/spinlock.h | 63 +-- include/asm-s390/spinlock_types.h | 21 + include/asm-sh/spinlock.h | 61 +-- include/asm-sh/spinlock_types.h | 22 + include/asm-sparc/spinlock.h | 140 +----- include/asm-sparc/spinlock_types.h | 20 + include/asm-sparc64/spinlock.h | 160 +------ include/asm-sparc64/spinlock_types.h | 20 + include/asm-x86_64/spinlock.h | 164 ++----- include/asm-x86_64/spinlock_types.h | 20 + include/linux/bit_spinlock.h | 77 ++++ include/linux/jbd.h | 1 + include/linux/spinlock.h | 627 ++++++--------------------- include/linux/spinlock_api_smp.h | 57 +++ include/linux/spinlock_api_up.h | 80 ++++ include/linux/spinlock_types.h | 67 +++ include/linux/spinlock_types_up.h | 51 +++ include/linux/spinlock_up.h | 74 ++++ kernel/Makefile | 1 + kernel/sched.c | 4 + kernel/spinlock.c | 15 +- lib/Makefile | 1 + lib/dec_and_lock.c | 3 - lib/kernel_lock.c | 3 +- lib/spinlock_debug.c | 257 +++++++++++ 69 files changed, 1591 insertions(+), 2871 deletions(-) delete mode 100644 arch/parisc/lib/debuglocks.c delete mode 100644 arch/sparc/lib/debuglocks.c delete mode 100644 arch/sparc64/lib/debuglocks.c create mode 100644 include/asm-alpha/spinlock_types.h create mode 100644 include/asm-arm/spinlock_types.h create mode 100644 include/asm-i386/spinlock_types.h create mode 100644 include/asm-ia64/spinlock_types.h create mode 100644 include/asm-m32r/spinlock_types.h create mode 100644 include/asm-mips/spinlock_types.h create mode 100644 include/asm-parisc/spinlock_types.h create mode 100644 include/asm-ppc/spinlock_types.h create mode 100644 include/asm-ppc64/spinlock_types.h create mode 100644 include/asm-s390/spinlock_types.h create mode 100644 include/asm-sh/spinlock_types.h create mode 100644 include/asm-sparc/spinlock_types.h create mode 100644 include/asm-sparc64/spinlock_types.h create mode 100644 include/asm-x86_64/spinlock_types.h create mode 100644 include/linux/bit_spinlock.h create mode 100644 include/linux/spinlock_api_smp.h create mode 100644 include/linux/spinlock_api_up.h create mode 100644 include/linux/spinlock_types.h create mode 100644 include/linux/spinlock_types_up.h create mode 100644 include/linux/spinlock_up.h create mode 100644 lib/spinlock_debug.c diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index fc5ef90c4fc95..24ae9a3660737 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -185,15 +185,6 @@ EXPORT_SYMBOL(smp_num_cpus); EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_call_function_on_cpu); EXPORT_SYMBOL(_atomic_dec_and_lock); -#ifdef CONFIG_DEBUG_SPINLOCK -EXPORT_SYMBOL(_raw_spin_unlock); -EXPORT_SYMBOL(debug_spin_lock); -EXPORT_SYMBOL(debug_spin_trylock); -#endif -#ifdef CONFIG_DEBUG_RWLOCK -EXPORT_SYMBOL(_raw_write_lock); -EXPORT_SYMBOL(_raw_read_lock); -#endif EXPORT_SYMBOL(cpu_present_mask); #endif /* CONFIG_SMP */ diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index e211aa7404e61..da0be34657915 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -989,175 +989,3 @@ flush_icache_user_range(struct vm_area_struct *vma, struct page *page, preempt_enable(); } - -#ifdef CONFIG_DEBUG_SPINLOCK -void -_raw_spin_unlock(spinlock_t * lock) -{ - mb(); - lock->lock = 0; - - lock->on_cpu = -1; - lock->previous = NULL; - lock->task = NULL; - lock->base_file = "none"; - lock->line_no = 0; -} - -void -debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no) -{ - long tmp; - long stuck; - void *inline_pc = __builtin_return_address(0); - unsigned long started = jiffies; - int printed = 0; - int cpu = smp_processor_id(); - - stuck = 1L << 30; - try_again: - - /* Use sub-sections to put the actual loop at the end - of this object file's text section so as to perfect - branch prediction. */ - __asm__ __volatile__( - "1: ldl_l %0,%1\n" - " subq %2,1,%2\n" - " blbs %0,2f\n" - " or %0,1,%0\n" - " stl_c %0,%1\n" - " beq %0,3f\n" - "4: mb\n" - ".subsection 2\n" - "2: ldl %0,%1\n" - " subq %2,1,%2\n" - "3: blt %2,4b\n" - " blbs %0,2b\n" - " br 1b\n" - ".previous" - : "=r" (tmp), "=m" (lock->lock), "=r" (stuck) - : "m" (lock->lock), "2" (stuck) : "memory"); - - if (stuck < 0) { - printk(KERN_WARNING - "%s:%d spinlock stuck in %s at %p(%d)" - " owner %s at %p(%d) %s:%d\n", - base_file, line_no, - current->comm, inline_pc, cpu, - lock->task->comm, lock->previous, - lock->on_cpu, lock->base_file, lock->line_no); - stuck = 1L << 36; - printed = 1; - goto try_again; - } - - /* Exiting. Got the lock. */ - lock->on_cpu = cpu; - lock->previous = inline_pc; - lock->task = current; - lock->base_file = base_file; - lock->line_no = line_no; - - if (printed) { - printk(KERN_WARNING - "%s:%d spinlock grabbed in %s at %p(%d) %ld ticks\n", - base_file, line_no, current->comm, inline_pc, - cpu, jiffies - started); - } -} - -int -debug_spin_trylock(spinlock_t * lock, const char *base_file, int line_no) -{ - int ret; - if ((ret = !test_and_set_bit(0, lock))) { - lock->on_cpu = smp_processor_id(); - lock->previous = __builtin_return_address(0); - lock->task = current; - } else { - lock->base_file = base_file; - lock->line_no = line_no; - } - return ret; -} -#endif /* CONFIG_DEBUG_SPINLOCK */ - -#ifdef CONFIG_DEBUG_RWLOCK -void _raw_write_lock(rwlock_t * lock) -{ - long regx, regy; - int stuck_lock, stuck_reader; - void *inline_pc = __builtin_return_address(0); - - try_again: - - stuck_lock = 1<<30; - stuck_reader = 1<<30; - - __asm__ __volatile__( - "1: ldl_l %1,%0\n" - " blbs %1,6f\n" - " blt %1,8f\n" - " mov 1,%1\n" - " stl_c %1,%0\n" - " beq %1,6f\n" - "4: mb\n" - ".subsection 2\n" - "6: blt %3,4b # debug\n" - " subl %3,1,%3 # debug\n" - " ldl %1,%0\n" - " blbs %1,6b\n" - "8: blt %4,4b # debug\n" - " subl %4,1,%4 # debug\n" - " ldl %1,%0\n" - " blt %1,8b\n" - " br 1b\n" - ".previous" - : "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (regy), - "=&r" (stuck_lock), "=&r" (stuck_reader) - : "m" (*(volatile int *)lock), "3" (stuck_lock), "4" (stuck_reader) : "memory"); - - if (stuck_lock < 0) { - printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc); - goto try_again; - } - if (stuck_reader < 0) { - printk(KERN_WARNING "write_lock stuck on readers at %p\n", - inline_pc); - goto try_again; - } -} - -void _raw_read_lock(rwlock_t * lock) -{ - long regx; - int stuck_lock; - void *inline_pc = __builtin_return_address(0); - - try_again: - - stuck_lock = 1<<30; - - __asm__ __volatile__( - "1: ldl_l %1,%0;" - " blbs %1,6f;" - " subl %1,2,%1;" - " stl_c %1,%0;" - " beq %1,6f;" - "4: mb\n" - ".subsection 2\n" - "6: ldl %1,%0;" - " blt %2,4b # debug\n" - " subl %2,1,%2 # debug\n" - " blbs %1,6b;" - " br 1b\n" - ".previous" - : "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (stuck_lock) - : "m" (*(volatile int *)lock), "2" (stuck_lock) : "memory"); - - if (stuck_lock < 0) { - printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc); - goto try_again; - } -} -#endif /* CONFIG_DEBUG_RWLOCK */ diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 4ebbf3974381a..8d484204a3ff6 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -491,12 +491,7 @@ init_handler_platform (pal_min_state_area_t *ms, unw_init_from_interruption(&info, current, pt, sw); ia64_do_show_stack(&info, NULL); -#ifdef CONFIG_SMP - /* read_trylock() would be handy... */ - if (!tasklist_lock.write_lock) - read_lock(&tasklist_lock); -#endif - { + if (read_trylock(&tasklist_lock)) { struct task_struct *g, *t; do_each_thread (g, t) { if (t == current) @@ -506,10 +501,6 @@ init_handler_platform (pal_min_state_area_t *ms, show_stack(t, NULL); } while_each_thread (g, t); } -#ifdef CONFIG_SMP - if (!tasklist_lock.write_lock) - read_unlock(&tasklist_lock); -#endif printk("\nINIT dump complete. Please reboot now.\n"); while (1); /* hang city if no debugger */ diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c index 48b187f2d2b35..a4576ac7e8702 100644 --- a/arch/m32r/kernel/smp.c +++ b/arch/m32r/kernel/smp.c @@ -892,7 +892,6 @@ unsigned long send_IPI_mask_phys(cpumask_t physid_mask, int ipi_num, int try) { spinlock_t *ipilock; - unsigned long flags = 0; volatile unsigned long *ipicr_addr; unsigned long ipicr_val; unsigned long my_physid_mask; @@ -916,50 +915,27 @@ unsigned long send_IPI_mask_phys(cpumask_t physid_mask, int ipi_num, * write IPICRi (send IPIi) * unlock ipi_lock[i] */ + spin_lock(ipilock); __asm__ __volatile__ ( - ";; LOCK ipi_lock[i] \n\t" + ";; CHECK IPICRi == 0 \n\t" ".fillinsn \n" "1: \n\t" - "mvfc %1, psw \n\t" - "clrpsw #0x40 -> nop \n\t" - DCACHE_CLEAR("r4", "r5", "%2") - "lock r4, @%2 \n\t" - "addi r4, #-1 \n\t" - "unlock r4, @%2 \n\t" - "mvtc %1, psw \n\t" - "bnez r4, 2f \n\t" - LOCK_SECTION_START(".balign 4 \n\t") - ".fillinsn \n" - "2: \n\t" - "ld r4, @%2 \n\t" - "blez r4, 2b \n\t" + "ld %0, @%1 \n\t" + "and %0, %4 \n\t" + "beqz %0, 2f \n\t" + "bnez %3, 3f \n\t" "bra 1b \n\t" - LOCK_SECTION_END - ";; CHECK IPICRi == 0 \n\t" - ".fillinsn \n" - "3: \n\t" - "ld %0, @%3 \n\t" - "and %0, %6 \n\t" - "beqz %0, 4f \n\t" - "bnez %5, 5f \n\t" - "bra 3b \n\t" ";; WRITE IPICRi (send IPIi) \n\t" ".fillinsn \n" - "4: \n\t" - "st %4, @%3 \n\t" - ";; UNLOCK ipi_lock[i] \n\t" + "2: \n\t" + "st %2, @%1 \n\t" ".fillinsn \n" - "5: \n\t" - "ldi r4, #1 \n\t" - "st r4, @%2 \n\t" + "3: \n\t" : "=&r"(ipicr_val) - : "r"(flags), "r"(&ipilock->slock), "r"(ipicr_addr), - "r"(mask), "r"(try), "r"(my_physid_mask) - : "memory", "r4" -#ifdef CONFIG_CHIP_M32700_TS1 - , "r5" -#endif /* CONFIG_CHIP_M32700_TS1 */ + : "r"(ipicr_addr), "r"(mask), "r"(try), "r"(my_physid_mask) + : "memory" ); + spin_unlock(ipilock); return ipicr_val; } diff --git a/arch/mips/lib/dec_and_lock.c b/arch/mips/lib/dec_and_lock.c index e44e9579bd36d..fd82c84a93b72 100644 --- a/arch/mips/lib/dec_and_lock.c +++ b/arch/mips/lib/dec_and_lock.c @@ -20,14 +20,7 @@ * has a cmpxchg, and where atomic->value is an int holding * the value of the atomic (i.e. the high bits aren't used * for a lock or anything like that). - * - * N.B. ATOMIC_DEC_AND_LOCK gets defined in include/linux/spinlock.h - * if spinlocks are empty and thus atomic_dec_and_lock is defined - * to be atomic_dec_and_test - in that case we don't need it - * defined here as well. */ - -#ifndef ATOMIC_DEC_AND_LOCK int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { int counter; @@ -52,4 +45,3 @@ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) } EXPORT_SYMBOL(_atomic_dec_and_lock); -#endif /* ATOMIC_DEC_AND_LOCK */ diff --git a/arch/parisc/lib/Makefile b/arch/parisc/lib/Makefile index 7bf705676297a..5f2e6904d14ae 100644 --- a/arch/parisc/lib/Makefile +++ b/arch/parisc/lib/Makefile @@ -5,5 +5,3 @@ lib-y := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o memcpy.o obj-y := iomap.o - -lib-$(CONFIG_SMP) += debuglocks.o diff --git a/arch/parisc/lib/bitops.c b/arch/parisc/lib/bitops.c index 2de182f6fe8a9..90f400b102822 100644 --- a/arch/parisc/lib/bitops.c +++ b/arch/parisc/lib/bitops.c @@ -13,8 +13,8 @@ #include <asm/atomic.h> #ifdef CONFIG_SMP -spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned = { - [0 ... (ATOMIC_HASH_SIZE-1)] = SPIN_LOCK_UNLOCKED +raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned = { + [0 ... (ATOMIC_HASH_SIZE-1)] = __RAW_SPIN_LOCK_UNLOCKED }; #endif diff --git a/arch/parisc/lib/debuglocks.c b/arch/parisc/lib/debuglocks.c deleted file mode 100644 index 1b33fe6e5b7a1..0000000000000 --- a/arch/parisc/lib/debuglocks.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Debugging versions of SMP locking primitives. - * - * Copyright (C) 2004 Thibaut VARENE <varenet@parisc-linux.org> - * - * Some code stollen from alpha & sparc64 ;) - * - * 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 - * - * We use pdc_printf() throughout the file for all output messages, to avoid - * losing messages because of disabled interrupts. Since we're using these - * messages for debugging purposes, it makes sense not to send them to the - * linux console. - */ - - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include <linux/hardirq.h> /* in_interrupt() */ -#include <asm/system.h> -#include <asm/hardirq.h> /* in_interrupt() */ -#include <asm/pdc.h> - -#undef INIT_STUCK -#define INIT_STUCK 1L << 30 - -#ifdef CONFIG_DEBUG_SPINLOCK - - -void _dbg_spin_lock(spinlock_t * lock, const char *base_file, int line_no) -{ - volatile unsigned int *a; - long stuck = INIT_STUCK; - void *inline_pc = __builtin_return_address(0); - unsigned long started = jiffies; - int printed = 0; - int cpu = smp_processor_id(); - -try_again: - - /* Do the actual locking */ - /* <T-Bone> ggg: we can't get stuck on the outter loop? - * <ggg> T-Bone: We can hit the outer loop - * alot if multiple CPUs are constantly racing for a lock - * and the backplane is NOT fair about which CPU sees - * the update first. But it won't hang since every failed - * attempt will drop us back into the inner loop and - * decrement `stuck'. - * <ggg> K-class and some of the others are NOT fair in the HW - * implementation so we could see false positives. - * But fixing the lock contention is easier than - * fixing the HW to be fair. - * <tausq> __ldcw() returns 1 if we get the lock; otherwise we - * spin until the value of the lock changes, or we time out. - */ - mb(); - a = __ldcw_align(lock); - while (stuck && (__ldcw(a) == 0)) - while ((*a == 0) && --stuck); - mb(); - - if (unlikely(stuck <= 0)) { - pdc_printf( - "%s:%d: spin_lock(%s/%p) stuck in %s at %p(%d)" - " owned by %s:%d in %s at %p(%d)\n", - base_file, line_no, lock->module, lock, - current->comm, inline_pc, cpu, - lock->bfile, lock->bline, lock->task->comm, - lock->previous, lock->oncpu); - stuck = INIT_STUCK; - printed = 1; - goto try_again; - } - - /* Exiting. Got the lock. */ - lock->oncpu = cpu; - lock->previous = inline_pc; - lock->task = current; - lock->bfile = (char *)base_file; - lock->bline = line_no; - - if (unlikely(printed)) { - pdc_printf( - "%s:%d: spin_lock grabbed in %s at %p(%d) %ld ticks\n", - base_file, line_no, current->comm, inline_pc, - cpu, jiffies - started); - } -} - -void _dbg_spin_unlock(spinlock_t * lock, const char *base_file, int line_no) -{ - CHECK_LOCK(lock); - volatile unsigned int *a; - mb(); - a = __ldcw_align(lock); - if (unlikely((*a != 0) && lock->babble)) { - lock->babble--; - pdc_printf( - "%s:%d: spin_unlock(%s:%p) not locked\n", - base_file, line_no, lock->module, lock); - } - *a = 1; - mb(); -} - -int _dbg_spin_trylock(spinlock_t * lock, const char *base_file, int line_no) -{ - int ret; - volatile unsigned int *a; - mb(); - a = __ldcw_align(lock); - ret = (__ldcw(a) != 0); - mb(); - if (ret) { - lock->oncpu = smp_processor_id(); - lock->previous = __builtin_return_address(0); - lock->task = current; - } else { - lock->bfile = (char *)base_file; - lock->bline = line_no; - } - return ret; -} - -#endif /* CONFIG_DEBUG_SPINLOCK */ - -#ifdef CONFIG_DEBUG_RWLOCK - -/* Interrupts trouble detailed explanation, thx Grant: - * - * o writer (wants to modify data) attempts to acquire the rwlock - * o He gets the write lock. - * o Interupts are still enabled, we take an interrupt with the - * write still holding the lock. - * o interrupt handler tries to acquire the rwlock for read. - * o deadlock since the writer can't release it at this point. - * - * In general, any use of spinlocks that competes between "base" - * level and interrupt level code will risk deadlock. Interrupts - * need to be disabled in the base level routines to avoid it. - * Or more precisely, only the IRQ the base level routine - * is competing with for the lock. But it's more efficient/faster - * to just disable all interrupts on that CPU to guarantee - * once it gets the lock it can release it quickly too. - */ - -void _dbg_write_lock(rwlock_t *rw, const char *bfile, int bline) -{ - void *inline_pc = __builtin_return_address(0); - unsigned long started = jiffies; - long stuck = INIT_STUCK; - int printed = 0; - int cpu = smp_processor_id(); - - if(unlikely(in_interrupt())) { /* acquiring write lock in interrupt context, bad idea */ - pdc_printf("write_lock caller: %s:%d, IRQs enabled,\n", bfile, bline); - BUG(); - } - - /* Note: if interrupts are disabled (which is most likely), the printk - will never show on the console. We might need a polling method to flush - the dmesg buffer anyhow. */ - -retry: - _raw_spin_lock(&rw->lock); - - if(rw->counter != 0) { - /* this basically never happens */ - _raw_spin_unlock(&rw->lock); - - stuck--; - if ((unlikely(stuck <= 0)) && (rw->counter < 0)) { - pdc_printf( - "%s:%d: write_lock stuck on writer" - " in %s at %p(%d) %ld ticks\n", - bfile, bline, current->comm, inline_pc, - cpu, jiffies - started); - stuck = INIT_STUCK; - printed = 1; - } - else if (unlikely(stuck <= 0)) { - pdc_printf( - "%s:%d: write_lock stuck on reader" - " in %s at %p(%d) %ld ticks\n", - bfile, bline, current->comm, inline_pc, - cpu, jiffies - started); - stuck = INIT_STUCK; - printed = 1; - } - - while(rw->counter != 0); - - goto retry; - } - - /* got it. now leave without unlocking */ - rw->counter = -1; /* remember we are locked */ - - if (unlikely(printed)) { - pdc_printf( - "%s:%d: write_lock grabbed in %s at %p(%d) %ld ticks\n", - bfile, bline, current->comm, inline_pc, - cpu, jiffies - started); - } -} - -int _dbg_write_trylock(rwlock_t *rw, const char *bfile, int bline) -{ -#if 0 - void *inline_pc = __builtin_return_address(0); - int cpu = smp_processor_id(); -#endif - - if(unlikely(in_interrupt())) { /* acquiring write lock in interrupt context, bad idea */ - pdc_printf("write_lock caller: %s:%d, IRQs enabled,\n", bfile, bline); - BUG(); - } - - /* Note: if interrupts are disabled (which is most likely), the printk - will never show on the console. We might need a polling method to flush - the dmesg buffer anyhow. */ - - _raw_spin_lock(&rw->lock); - - if(rw->counter != 0) { - /* this basically never happens */ - _raw_spin_unlock(&rw->lock); - return 0; - } - - /* got it. now leave without unlocking */ - rw->counter = -1; /* remember we are locked */ -#if 0 - pdc_printf("%s:%d: try write_lock grabbed in %s at %p(%d)\n", - bfile, bline, current->comm, inline_pc, cpu); -#endif - return 1; -} - -void _dbg_read_lock(rwlock_t * rw, const char *bfile, int bline) -{ -#if 0 - void *inline_pc = __builtin_return_address(0); - unsigned long started = jiffies; - int cpu = smp_processor_id(); -#endif - unsigned long flags; - - local_irq_save(flags); - _raw_spin_lock(&rw->lock); - - rw->counter++; -#if 0 - pdc_printf( - "%s:%d: read_lock grabbed in %s at %p(%d) %ld ticks\n", - bfile, bline, current->comm, inline_pc, - cpu, jiffies - started); -#endif - _raw_spin_unlock(&rw->lock); - local_irq_restore(flags); -} - -#endif /* CONFIG_DEBUG_RWLOCK */ diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile index 1c380e67d4357..f1e1fb4144f03 100644 --- a/arch/ppc/lib/Makefile +++ b/arch/ppc/lib/Makefile @@ -4,6 +4,5 @@ obj-y := checksum.o string.o strcase.o dec_and_lock.o div64.o -obj-$(CONFIG_SMP) += locks.o obj-$(CONFIG_8xx) += rheap.o obj-$(CONFIG_CPM2) += rheap.o diff --git a/arch/ppc/lib/dec_and_lock.c b/arch/ppc/lib/dec_and_lock.c index 4ee888070d914..b18f0d9a00fc7 100644 --- a/arch/ppc/lib/dec_and_lock.c +++ b/arch/ppc/lib/dec_and_lock.c @@ -11,14 +11,7 @@ * has a cmpxchg, and where atomic->value is an int holding * the value of the atomic (i.e. the high bits aren't used * for a lock or anything like that). - * - * N.B. ATOMIC_DEC_AND_LOCK gets defined in include/linux/spinlock.h - * if spinlocks are empty and thus atomic_dec_and_lock is defined - * to be atomic_dec_and_test - in that case we don't need it - * defined here as well. */ - -#ifndef ATOMIC_DEC_AND_LOCK int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { int counter; @@ -43,4 +36,3 @@ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) } EXPORT_SYMBOL(_atomic_dec_and_lock); -#endif /* ATOMIC_DEC_AND_LOCK */ diff --git a/arch/ppc64/lib/dec_and_lock.c b/arch/ppc64/lib/dec_and_lock.c index 6e8d8591708cb..7b9d4da5cf926 100644 --- a/arch/ppc64/lib/dec_and_lock.c +++ b/arch/ppc64/lib/dec_and_lock.c @@ -20,14 +20,7 @@ * has a cmpxchg, and where atomic->value is an int holding * the value of the atomic (i.e. the high bits aren't used * for a lock or anything like that). - * - * N.B. ATOMIC_DEC_AND_LOCK gets defined in include/linux/spinlock.h - * if spinlocks are empty and thus atomic_dec_and_lock is defined - * to be atomic_dec_and_test - in that case we don't need it - * defined here as well. */ - -#ifndef ATOMIC_DEC_AND_LOCK int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { int counter; @@ -52,4 +45,3 @@ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) } EXPORT_SYMBOL(_atomic_dec_and_lock); -#endif /* ATOMIC_DEC_AND_LOCK */ diff --git a/arch/ppc64/lib/locks.c b/arch/ppc64/lib/locks.c index ef70ef91abe26..033643ab69e0b 100644 --- a/arch/ppc64/lib/locks.c +++ b/arch/ppc64/lib/locks.c @@ -23,12 +23,12 @@ /* waiting for a spinlock... */ #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) -void __spin_yield(spinlock_t *lock) +void __spin_yield(raw_spinlock_t *lock) { unsigned int lock_value, holder_cpu, yield_count; struct paca_struct *holder_paca; - lock_value = lock->lock; + lock_value = lock->slock; if (lock_value == 0) return; holder_cpu = lock_value & 0xffff; @@ -38,7 +38,7 @@ void __spin_yield(spinlock_t *lock) if ((yield_count & 1) == 0) return; /* virtual cpu is currently running */ rmb(); - if (lock->lock != lock_value) + if (lock->slock != lock_value) return; /* something has changed */ #ifdef CONFIG_PPC_ISERIES HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, @@ -54,7 +54,7 @@ void __spin_yield(spinlock_t *lock) * This turns out to be the same for read and write locks, since * we only know the holder if it is write-locked. */ -void __rw_yield(rwlock_t *rw) +void __rw_yield(raw_rwlock_t *rw) { int lock_value; unsigned int holder_cpu, yield_count; @@ -82,9 +82,9 @@ void __rw_yield(rwlock_t *rw) } #endif -void spin_unlock_wait(spinlock_t *lock) +void __raw_spin_unlock_wait(raw_spinlock_t *lock) { - while (lock->lock) { + while (lock->slock) { HMT_low(); if (SHARED_PROCESSOR) __spin_yield(lock); @@ -92,4 +92,4 @@ void spin_unlock_wait(spinlock_t *lock) HMT_medium(); } -EXPORT_SYMBOL(spin_unlock_wait); +EXPORT_SYMBOL(__raw_spin_unlock_wait); diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index 888b5596c195d..2dc14e9c83276 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -36,7 +36,7 @@ _diag44(void) } void -_raw_spin_lock_wait(spinlock_t *lp, unsigned int pc) +_raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc) { int count = spin_retry; @@ -53,7 +53,7 @@ _raw_spin_lock_wait(spinlock_t *lp, unsigned int pc) EXPORT_SYMBOL(_raw_spin_lock_wait); int -_raw_spin_trylock_retry(spinlock_t *lp, unsigned int pc) +_raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc) { int count = spin_retry; @@ -67,7 +67,7 @@ _raw_spin_trylock_retry(spinlock_t *lp, unsigned int pc) EXPORT_SYMBOL(_raw_spin_trylock_retry); void -_raw_read_lock_wait(rwlock_t *rw) +_raw_read_lock_wait(raw_rwlock_t *rw) { unsigned int old; int count = spin_retry; @@ -86,7 +86,7 @@ _raw_read_lock_wait(rwlock_t *rw) EXPORT_SYMBOL(_raw_read_lock_wait); int -_raw_read_trylock_retry(rwlock_t *rw) +_raw_read_trylock_retry(raw_rwlock_t *rw) { unsigned int old; int count = spin_retry; @@ -102,7 +102,7 @@ _raw_read_trylock_retry(rwlock_t *rw) EXPORT_SYMBOL(_raw_read_trylock_retry); void -_raw_write_lock_wait(rwlock_t *rw) +_raw_write_lock_wait(raw_rwlock_t *rw) { int count = spin_retry; @@ -119,7 +119,7 @@ _raw_write_lock_wait(rwlock_t *rw) EXPORT_SYMBOL(_raw_write_lock_wait); int -_raw_write_trylock_retry(rwlock_t *rw) +_raw_write_trylock_retry(raw_rwlock_t *rw) { int count = spin_retry; diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 5d974a2b735a9..f84809333624a 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -114,17 +114,7 @@ DOT_ALIAS2(unsigned, urem, unsigned, unsigned) /* used by various drivers */ EXPORT_SYMBOL(sparc_cpu_model); EXPORT_SYMBOL(kernel_thread); -#ifdef CONFIG_DEBUG_SPINLOCK #ifdef CONFIG_SMP -EXPORT_SYMBOL(_do_spin_lock); -EXPORT_SYMBOL(_do_spin_unlock); -EXPORT_SYMBOL(_spin_trylock); -EXPORT_SYMBOL(_do_read_lock); -EXPORT_SYMBOL(_do_read_unlock); -EXPORT_SYMBOL(_do_write_lock); -EXPORT_SYMBOL(_do_write_unlock); -#endif -#else // XXX find what uses (or used) these. EXPORT_SYMBOL(___rw_read_enter); EXPORT_SYMBOL(___rw_read_exit); diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index 2296ff9dc47aa..fa50069460621 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -9,5 +9,3 @@ lib-y := mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ copy_user.o locks.o atomic.o atomic32.o bitops.o \ lshrdi3.o ashldi3.o rwsem.o muldi3.o bitext.o - -lib-$(CONFIG_DEBUG_SPINLOCK) += debuglocks.o diff --git a/arch/sparc/lib/debuglocks.c b/arch/sparc/lib/debuglocks.c deleted file mode 100644 index fb182352782c5..0000000000000 --- a/arch/sparc/lib/debuglocks.c +++ /dev/null @@ -1,202 +0,0 @@ -/* $Id: debuglocks.c,v 1.11 2001/09/20 00:35:31 davem Exp $ - * debuglocks.c: Debugging versions of SMP locking primitives. - * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au) - */ - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/threads.h> /* For NR_CPUS */ -#include <linux/spinlock.h> -#include <asm/psr.h> -#include <asm/system.h> - -#ifdef CONFIG_SMP - -/* Some notes on how these debugging routines work. When a lock is acquired - * an extra debugging member lock->owner_pc is set to the caller of the lock - * acquisition routine. Right before releasing a lock, the debugging program - * counter is cleared to zero. - * - * Furthermore, since PC's are 4 byte aligned on Sparc, we stuff the CPU - * number of the owner in the lowest two bits. - */ - -#define STORE_CALLER(A) __asm__ __volatile__("mov %%i7, %0" : "=r" (A)); - -static inline void show(char *str, spinlock_t *lock, unsigned long caller) -{ - int cpu = smp_processor_id(); - - printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str, - lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); -} - -static inline void show_read(char *str, rwlock_t *lock, unsigned long caller) -{ - int cpu = smp_processor_id(); - - printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", str, - lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); -} - -static inline void show_write(char *str, rwlock_t *lock, unsigned long caller) -{ - int cpu = smp_processor_id(); - int i; - - printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)", str, - lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); - - for(i = 0; i < NR_CPUS; i++) - printk(" reader[%d]=%08lx", i, lock->reader_pc[i]); - - printk("\n"); -} - -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -void _do_spin_lock(spinlock_t *lock, char *str) -{ - unsigned long caller; - unsigned long val; - int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - - STORE_CALLER(caller); - -again: - __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); - if(val) { - while(lock->lock) { - if (!--stuck) { - show(str, lock, caller); - stuck = INIT_STUCK; - } - barrier(); - } - goto again; - } - lock->owner_pc = (cpu & 3) | (caller & ~3); -} - -int _spin_trylock(spinlock_t *lock) -{ - unsigned long val; - unsigned long caller; - int cpu = smp_processor_id(); - - STORE_CALLER(caller); - - __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); - if(!val) { - /* We got it, record our identity for debugging. */ - lock->owner_pc = (cpu & 3) | (caller & ~3); - } - return val == 0; -} - -void _do_spin_unlock(spinlock_t *lock) -{ - lock->owner_pc = 0; - barrier(); - lock->lock = 0; -} - -void _do_read_lock(rwlock_t *rw, char *str) -{ - unsigned long caller; - unsigned long val; - int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - - STORE_CALLER(caller); - -wlock_again: - __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff) { - if (!--stuck) { - show_read(str, rw, caller); - stuck = INIT_STUCK; - } - barrier(); - } - goto wlock_again; - } - - rw->reader_pc[cpu] = caller; - barrier(); - rw->lock++; -} - -void _do_read_unlock(rwlock_t *rw, char *str) -{ - unsigned long caller; - unsigned long val; - int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - - STORE_CALLER(caller); - -wlock_again: - __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff) { - if (!--stuck) { - show_read(str, rw, caller); - stuck = INIT_STUCK; - } - barrier(); - } - goto wlock_again; - } - - rw->reader_pc[cpu] = 0; - barrier(); - rw->lock -= 0x1ff; -} - -void _do_write_lock(rwlock_t *rw, char *str) -{ - unsigned long caller; - unsigned long val; - int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - - STORE_CALLER(caller); - -wlock_again: - __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { -wlock_wait: - while(rw->lock) { - if (!--stuck) { - show_write(str, rw, caller); - stuck = INIT_STUCK; - } - barrier(); - } - goto wlock_again; - } - - if (rw->lock & ~0xff) { - *(((unsigned char *)&rw->lock)+3) = 0; - barrier(); - goto wlock_wait; - } - - barrier(); - rw->owner_pc = (cpu & 3) | (caller & ~3); -} - -void _do_write_unlock(rwlock_t *rw) -{ - rw->owner_pc = 0; - barrier(); - rw->lock = 0; -} - -#endif /* SMP */ diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 66255434128a2..7d10b03970919 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -607,11 +607,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, struct thread_info *t = p->thread_info; char *child_trap_frame; -#ifdef CONFIG_DEBUG_SPINLOCK - p->thread.smp_lock_count = 0; - p->thread.smp_lock_pc = 0; -#endif - /* Calculate offset to stack_frame & pt_regs */ child_trap_frame = ((char *)t) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ)); memcpy(child_trap_frame, (((struct sparc_stackf *)regs)-1), (TRACEREG_SZ+STACKFRAME_SZ)); diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 7d9a0f6c437dc..cbb5e59824e56 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -115,17 +115,12 @@ EXPORT_PER_CPU_SYMBOL(__cpu_data); /* used by various drivers */ #ifdef CONFIG_SMP -#ifndef CONFIG_DEBUG_SPINLOCK /* Out of line rw-locking implementation. */ EXPORT_SYMBOL(__read_lock); EXPORT_SYMBOL(__read_unlock); EXPORT_SYMBOL(__write_lock); EXPORT_SYMBOL(__write_unlock); EXPORT_SYMBOL(__write_trylock); -/* Out of line spin-locking implementation. */ -EXPORT_SYMBOL(_raw_spin_lock); -EXPORT_SYMBOL(_raw_spin_lock_flags); -#endif /* Hard IRQ locking */ EXPORT_SYMBOL(synchronize_irq); diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile index 40dbeec7e5d6a..d968aebe83b28 100644 --- a/arch/sparc64/lib/Makefile +++ b/arch/sparc64/lib/Makefile @@ -14,7 +14,6 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \ copy_in_user.o user_fixup.o memmove.o \ mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o -lib-$(CONFIG_DEBUG_SPINLOCK) += debuglocks.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o obj-y += iomap.o diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c deleted file mode 100644 index f5f0b5586f01a..0000000000000 --- a/arch/sparc64/lib/debuglocks.c +++ /dev/null @@ -1,366 +0,0 @@ -/* $Id: debuglocks.c,v 1.9 2001/11/17 00:10:48 davem Exp $ - * debuglocks.c: Debugging versions of SMP locking primitives. - * - * Copyright (C) 1998 David S. Miller (davem@redhat.com) - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include <asm/system.h> - -#ifdef CONFIG_SMP - -static inline void show (char *str, spinlock_t *lock, unsigned long caller) -{ - int cpu = smp_processor_id(); - - printk("%s(%p) CPU#%d stuck at %08x, owner PC(%08x):CPU(%x)\n", - str, lock, cpu, (unsigned int) caller, - lock->owner_pc, lock->owner_cpu); -} - -static inline void show_read (char *str, rwlock_t *lock, unsigned long caller) -{ - int cpu = smp_processor_id(); - - printk("%s(%p) CPU#%d stuck at %08x, writer PC(%08x):CPU(%x)\n", - str, lock, cpu, (unsigned int) caller, - lock->writer_pc, lock->writer_cpu); -} - -static inline void show_write (char *str, rwlock_t *lock, unsigned long caller) -{ - int cpu = smp_processor_id(); - int i; - - printk("%s(%p) CPU#%d stuck at %08x\n", - str, lock, cpu, (unsigned int) caller); - printk("Writer: PC(%08x):CPU(%x)\n", - lock->writer_pc, lock->writer_cpu); - printk("Readers:"); - for (i = 0; i < NR_CPUS; i++) - if (lock->reader_pc[i]) - printk(" %d[%08x]", i, lock->reader_pc[i]); - printk("\n"); -} - -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -void _do_spin_lock(spinlock_t *lock, char *str, unsigned long caller) -{ - unsigned long val; - int stuck = INIT_STUCK; - int cpu = get_cpu(); - int shown = 0; - -again: - __asm__ __volatile__("ldstub [%1], %0" - : "=r" (val) - : "r" (&(lock->lock)) - : "memory"); - membar_storeload_storestore(); - if (val) { - while (lock->lock) { - if (!--stuck) { - if (shown++ <= 2) - show(str, lock, caller); - stuck = INIT_STUCK; - } - rmb(); - } - goto again; - } - lock->owner_pc = ((unsigned int)caller); - lock->owner_cpu = cpu; - current->thread.smp_lock_count++; - current->thread.smp_lock_pc = ((unsigned int)caller); - - put_cpu(); -} - -int _do_spin_trylock(spinlock_t *lock, unsigned long caller) -{ - unsigned long val; - int cpu = get_cpu(); - - __asm__ __volatile__("ldstub [%1], %0" - : "=r" (val) - : "r" (&(lock->lock)) - : "memory"); - membar_storeload_storestore(); - if (!val) { - lock->owner_pc = ((unsigned int)caller); - lock->owner_cpu = cpu; - current->thread.smp_lock_count++; - current->thread.smp_lock_pc = ((unsigned int)caller); - } - - put_cpu(); - - return val == 0; -} - -void _do_spin_unlock(spinlock_t *lock) -{ - lock->owner_pc = 0; - lock->owner_cpu = NO_PROC_ID; - membar_storestore_loadstore(); - lock->lock = 0; - current->thread.smp_lock_count--; -} - -/* Keep INIT_STUCK the same... */ - -void _do_read_lock(rwlock_t *rw, char *str, unsigned long caller) -{ - unsigned long val; - int stuck = INIT_STUCK; - int cpu = get_cpu(); - int shown = 0; - -wlock_again: - /* Wait for any writer to go away. */ - while (((long)(rw->lock)) < 0) { - if (!--stuck) { - if (shown++ <= 2) - show_read(str, rw, caller); - stuck = INIT_STUCK; - } - rmb(); - } - /* Try once to increment the counter. */ - __asm__ __volatile__( -" ldx [%0], %%g1\n" -" brlz,a,pn %%g1, 2f\n" -" mov 1, %0\n" -" add %%g1, 1, %%g7\n" -" casx [%0], %%g1, %%g7\n" -" sub %%g1, %%g7, %0\n" -"2:" : "=r" (val) - : "0" (&(rw->lock)) - : "g1", "g7", "memory"); - membar_storeload_storestore(); - if (val) - goto wlock_again; - rw->reader_pc[cpu] = ((unsigned int)caller); - current->thread.smp_lock_count++; - current->thread.smp_lock_pc = ((unsigned int)caller); - - put_cpu(); -} - -void _do_read_unlock(rwlock_t *rw, char *str, unsigned long caller) -{ - unsigned long val; - int stuck = INIT_STUCK; - int cpu = get_cpu(); - int shown = 0; - - /* Drop our identity _first_. */ - rw->reader_pc[cpu] = 0; - current->thread.smp_lock_count--; -runlock_again: - /* Spin trying to decrement the counter using casx. */ - __asm__ __volatile__( -" membar #StoreLoad | #LoadLoad\n" -" ldx [%0], %%g1\n" -" sub %%g1, 1, %%g7\n" -" casx [%0], %%g1, %%g7\n" -" membar #StoreLoad | #StoreStore\n" -" sub %%g1, %%g7, %0\n" - : "=r" (val) - : "0" (&(rw->lock)) - : "g1", "g7", "memory"); - if (val) { - if (!--stuck) { - if (shown++ <= 2) - show_read(str, rw, caller); - stuck = INIT_STUCK; - } - goto runlock_again; - } - - put_cpu(); -} - -void _do_write_lock(rwlock_t *rw, char *str, unsigned long caller) -{ - unsigned long val; - int stuck = INIT_STUCK; - int cpu = get_cpu(); - int shown = 0; - -wlock_again: - /* Spin while there is another writer. */ - while (((long)rw->lock) < 0) { - if (!--stuck) { - if (shown++ <= 2) - show_write(str, rw, caller); - stuck = INIT_STUCK; - } - rmb(); - } - - /* Try to acuire the write bit. */ - __asm__ __volatile__( -" mov 1, %%g3\n" -" sllx %%g3, 63, %%g3\n" -" ldx [%0], %%g1\n" -" brlz,pn %%g1, 1f\n" -" or %%g1, %%g3, %%g7\n" -" casx [%0], %%g1, %%g7\n" -" membar #StoreLoad | #StoreStore\n" -" ba,pt %%xcc, 2f\n" -" sub %%g1, %%g7, %0\n" -"1: mov 1, %0\n" -"2:" : "=r" (val) - : "0" (&(rw->lock)) - : "g3", "g1", "g7", "memory"); - if (val) { - /* We couldn't get the write bit. */ - if (!--stuck) { - if (shown++ <= 2) - show_write(str, rw, caller); - stuck = INIT_STUCK; - } - goto wlock_again; - } - if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) { - /* Readers still around, drop the write - * lock, spin, and try again. - */ - if (!--stuck) { - if (shown++ <= 2) - show_write(str, rw, caller); - stuck = INIT_STUCK; - } - __asm__ __volatile__( -" mov 1, %%g3\n" -" sllx %%g3, 63, %%g3\n" -"1: ldx [%0], %%g1\n" -" andn %%g1, %%g3, %%g7\n" -" casx [%0], %%g1, %%g7\n" -" cmp %%g1, %%g7\n" -" membar #StoreLoad | #StoreStore\n" -" bne,pn %%xcc, 1b\n" -" nop" - : /* no outputs */ - : "r" (&(rw->lock)) - : "g3", "g1", "g7", "cc", "memory"); - while(rw->lock != 0) { - if (!--stuck) { - if (shown++ <= 2) - show_write(str, rw, caller); - stuck = INIT_STUCK; - } - rmb(); - } - goto wlock_again; - } - - /* We have it, say who we are. */ - rw->writer_pc = ((unsigned int)caller); - rw->writer_cpu = cpu; - current->thread.smp_lock_count++; - current->thread.smp_lock_pc = ((unsigned int)caller); - - put_cpu(); -} - -void _do_write_unlock(rwlock_t *rw, unsigned long caller) -{ - unsigned long val; - int stuck = INIT_STUCK; - int shown = 0; - - /* Drop our identity _first_ */ - rw->writer_pc = 0; - rw->writer_cpu = NO_PROC_ID; - current->thread.smp_lock_count--; -wlock_again: - __asm__ __volatile__( -" membar #StoreLoad | #LoadLoad\n" -" mov 1, %%g3\n" -" sllx %%g3, 63, %%g3\n" -" ldx [%0], %%g1\n" -" andn %%g1, %%g3, %%g7\n" -" casx [%0], %%g1, %%g7\n" -" membar #StoreLoad | #StoreStore\n" -" sub %%g1, %%g7, %0\n" - : "=r" (val) - : "0" (&(rw->lock)) - : "g3", "g1", "g7", "memory"); - if (val) { - if (!--stuck) { - if (shown++ <= 2) - show_write("write_unlock", rw, caller); - stuck = INIT_STUCK; - } - goto wlock_again; - } -} - -int _do_write_trylock(rwlock_t *rw, char *str, unsigned long caller) -{ - unsigned long val; - int cpu = get_cpu(); - - /* Try to acuire the write bit. */ - __asm__ __volatile__( -" mov 1, %%g3\n" -" sllx %%g3, 63, %%g3\n" -" ldx [%0], %%g1\n" -" brlz,pn %%g1, 1f\n" -" or %%g1, %%g3, %%g7\n" -" casx [%0], %%g1, %%g7\n" -" membar #StoreLoad | #StoreStore\n" -" ba,pt %%xcc, 2f\n" -" sub %%g1, %%g7, %0\n" -"1: mov 1, %0\n" -"2:" : "=r" (val) - : "0" (&(rw->lock)) - : "g3", "g1", "g7", "memory"); - - if (val) { - put_cpu(); - return 0; - } - - if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) { - /* Readers still around, drop the write - * lock, return failure. - */ - __asm__ __volatile__( -" mov 1, %%g3\n" -" sllx %%g3, 63, %%g3\n" -"1: ldx [%0], %%g1\n" -" andn %%g1, %%g3, %%g7\n" -" casx [%0], %%g1, %%g7\n" -" cmp %%g1, %%g7\n" -" membar #StoreLoad | #StoreStore\n" -" bne,pn %%xcc, 1b\n" -" nop" - : /* no outputs */ - : "r" (&(rw->lock)) - : "g3", "g1", "g7", "cc", "memory"); - - put_cpu(); - - return 0; - } - - /* We have it, say who we are. */ - rw->writer_pc = ((unsigned int)caller); - rw->writer_cpu = cpu; - current->thread.smp_lock_count++; - current->thread.smp_lock_pc = ((unsigned int)caller); - - put_cpu(); - - return 1; -} - -#endif /* CONFIG_SMP */ diff --git a/fs/buffer.c b/fs/buffer.c index 1c62203a4906e..6cbfceabd95d7 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -40,6 +40,7 @@ #include <linux/cpu.h> #include <linux/bitops.h> #include <linux/mpage.h> +#include <linux/bit_spinlock.h> static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); static void invalidate_bh_lrus(void); diff --git a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h index 80780dba9986f..8197c69eff44c 100644 --- a/include/asm-alpha/spinlock.h +++ b/include/asm-alpha/spinlock.h @@ -6,7 +6,6 @@ #include <linux/kernel.h> #include <asm/current.h> - /* * Simple spin lock operations. There are two variants, one clears IRQ's * on the local processor, one does not. @@ -14,43 +13,18 @@ * We make no fairness assumptions. They have a cost. */ -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_DEBUG_SPINLOCK - int on_cpu; - int line_no; - void *previous; - struct task_struct * task; - const char *base_file; -#endif -} spinlock_t; - -#ifdef CONFIG_DEBUG_SPINLOCK -#define SPIN_LOCK_UNLOCKED (spinlock_t){ 0, -1, 0, NULL, NULL, NULL } -#else -#define SPIN_LOCK_UNLOCKED (spinlock_t){ 0 } -#endif - -#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) -#define spin_is_locked(x) ((x)->lock != 0) -#define spin_unlock_wait(x) do { barrier(); } while ((x)->lock) - -#ifdef CONFIG_DEBUG_SPINLOCK -extern void _raw_spin_unlock(spinlock_t * lock); -extern void debug_spin_lock(spinlock_t * lock, const char *, int); -extern int debug_spin_trylock(spinlock_t * lock, const char *, int); -#define _raw_spin_lock(LOCK) \ - debug_spin_lock(LOCK, __BASE_FILE__, __LINE__) -#define _raw_spin_trylock(LOCK) \ - debug_spin_trylock(LOCK, __BASE_FILE__, __LINE__) -#else -static inline void _raw_spin_unlock(spinlock_t * lock) +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) +#define __raw_spin_is_locked(x) ((x)->lock != 0) +#define __raw_spin_unlock_wait(x) \ + do { cpu_relax(); } while ((x)->lock) + +static inline void __raw_spin_unlock(raw_spinlock_t * lock) { mb(); lock->lock = 0; } -static inline void _raw_spin_lock(spinlock_t * lock) +static inline void __raw_spin_lock(raw_spinlock_t * lock) { long tmp; @@ -70,80 +44,64 @@ static inline void _raw_spin_lock(spinlock_t * lock) : "m"(lock->lock) : "memory"); } -static inline int _raw_spin_trylock(spinlock_t *lock) +static inline int __raw_spin_trylock(raw_spinlock_t *lock) { return !test_and_set_bit(0, &lock->lock); } -#endif /* CONFIG_DEBUG_SPINLOCK */ - -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) /***********************************************************/ -typedef struct { - volatile unsigned int lock; -} rwlock_t; - -#define RW_LOCK_UNLOCKED (rwlock_t){ 0 } - -#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) - -static inline int read_can_lock(rwlock_t *lock) +static inline int __raw_read_can_lock(raw_rwlock_t *lock) { return (lock->lock & 1) == 0; } -static inline int write_can_lock(rwlock_t *lock) +static inline int __raw_write_can_lock(raw_rwlock_t *lock) { return lock->lock == 0; } -#ifdef CONFIG_DEBUG_RWLOCK -extern void _raw_write_lock(rwlock_t * lock); -extern void _raw_read_lock(rwlock_t * lock); -#else -static inline void _raw_write_lock(rwlock_t * lock) +static inline void __raw_read_lock(raw_rwlock_t *lock) { long regx; __asm__ __volatile__( "1: ldl_l %1,%0\n" - " bne %1,6f\n" - " lda %1,1\n" + " blbs %1,6f\n" + " subl %1,2,%1\n" " stl_c %1,%0\n" " beq %1,6f\n" " mb\n" ".subsection 2\n" "6: ldl %1,%0\n" - " bne %1,6b\n" + " blbs %1,6b\n" " br 1b\n" ".previous" : "=m" (*lock), "=&r" (regx) : "m" (*lock) : "memory"); } -static inline void _raw_read_lock(rwlock_t * lock) +static inline void __raw_write_lock(raw_rwlock_t *lock) { long regx; __asm__ __volatile__( "1: ldl_l %1,%0\n" - " blbs %1,6f\n" - " subl %1,2,%1\n" + " bne %1,6f\n" + " lda %1,1\n" " stl_c %1,%0\n" " beq %1,6f\n" " mb\n" ".subsection 2\n" "6: ldl %1,%0\n" - " blbs %1,6b\n" + " bne %1,6b\n" " br 1b\n" ".previous" : "=m" (*lock), "=&r" (regx) : "m" (*lock) : "memory"); } -#endif /* CONFIG_DEBUG_RWLOCK */ -static inline int _raw_read_trylock(rwlock_t * lock) +static inline int __raw_read_trylock(raw_rwlock_t * lock) { long regx; int success; @@ -165,7 +123,7 @@ static inline int _raw_read_trylock(rwlock_t * lock) return success; } -static inline int _raw_write_trylock(rwlock_t * lock) +static inline int __raw_write_trylock(raw_rwlock_t * lock) { long regx; int success; @@ -187,13 +145,7 @@ static inline int _raw_write_trylock(rwlock_t * lock) return success; } -static inline void _raw_write_unlock(rwlock_t * lock) -{ - mb(); - lock->lock = 0; -} - -static inline void _raw_read_unlock(rwlock_t * lock) +static inline void __raw_read_unlock(raw_rwlock_t * lock) { long regx; __asm__ __volatile__( @@ -209,4 +161,10 @@ static inline void _raw_read_unlock(rwlock_t * lock) : "m" (*lock) : "memory"); } +static inline void __raw_write_unlock(raw_rwlock_t * lock) +{ + mb(); + lock->lock = 0; +} + #endif /* _ALPHA_SPINLOCK_H */ diff --git a/include/asm-alpha/spinlock_types.h b/include/asm-alpha/spinlock_types.h new file mode 100644 index 0000000000000..8141eb5ebf0d2 --- /dev/null +++ b/include/asm-alpha/spinlock_types.h @@ -0,0 +1,20 @@ +#ifndef _ALPHA_SPINLOCK_TYPES_H +#define _ALPHA_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned int lock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile unsigned int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { 0 } + +#endif diff --git a/include/asm-arm/spinlock.h b/include/asm-arm/spinlock.h index 1f906d09b6880..cb4906b455558 100644 --- a/include/asm-arm/spinlock.h +++ b/include/asm-arm/spinlock.h @@ -16,21 +16,14 @@ * Unlocked value: 0 * Locked value: 1 */ -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } +#define __raw_spin_is_locked(x) ((x)->lock != 0) +#define __raw_spin_unlock_wait(lock) \ + do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0) -#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while (0) -#define spin_is_locked(x) ((x)->lock != 0) -#define spin_unlock_wait(x) do { barrier(); } while (spin_is_locked(x)) -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) -static inline void _raw_spin_lock(spinlock_t *lock) +static inline void __raw_spin_lock(raw_spinlock_t *lock) { unsigned long tmp; @@ -47,7 +40,7 @@ static inline void _raw_spin_lock(spinlock_t *lock) smp_mb(); } -static inline int _raw_spin_trylock(spinlock_t *lock) +static inline int __raw_spin_trylock(raw_spinlock_t *lock) { unsigned long tmp; @@ -67,7 +60,7 @@ static inline int _raw_spin_trylock(spinlock_t *lock) } } -static inline void _raw_spin_unlock(spinlock_t *lock) +static inline void __raw_spin_unlock(raw_spinlock_t *lock) { smp_mb(); @@ -80,23 +73,14 @@ static inline void _raw_spin_unlock(spinlock_t *lock) /* * RWLOCKS - */ -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; - -#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } -#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while (0) -#define rwlock_is_locked(x) (*((volatile unsigned int *)(x)) != 0) - -/* + * + * * Write locks are easy - we just set bit 31. When unlocking, we can * just write zero since the lock is exclusively held. */ -static inline void _raw_write_lock(rwlock_t *rw) +#define rwlock_is_locked(x) (*((volatile unsigned int *)(x)) != 0) + +static inline void __raw_write_lock(rwlock_t *rw) { unsigned long tmp; @@ -113,7 +97,7 @@ static inline void _raw_write_lock(rwlock_t *rw) smp_mb(); } -static inline int _raw_write_trylock(rwlock_t *rw) +static inline int __raw_write_trylock(rwlock_t *rw) { unsigned long tmp; @@ -133,7 +117,7 @@ static inline int _raw_write_trylock(rwlock_t *rw) } } -static inline void _raw_write_unlock(rwlock_t *rw) +static inline void __raw_write_unlock(raw_rwlock_t *rw) { smp_mb(); @@ -156,7 +140,7 @@ static inline void _raw_write_unlock(rwlock_t *rw) * currently active. However, we know we won't have any write * locks. */ -static inline void _raw_read_lock(rwlock_t *rw) +static inline void __raw_read_lock(raw_rwlock_t *rw) { unsigned long tmp, tmp2; @@ -173,7 +157,7 @@ static inline void _raw_read_lock(rwlock_t *rw) smp_mb(); } -static inline void _raw_read_unlock(rwlock_t *rw) +static inline void __raw_read_unlock(rwlock_t *rw) { unsigned long tmp, tmp2; @@ -190,6 +174,6 @@ static inline void _raw_read_unlock(rwlock_t *rw) : "cc"); } -#define _raw_read_trylock(lock) generic_raw_read_trylock(lock) +#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) #endif /* __ASM_SPINLOCK_H */ diff --git a/include/asm-arm/spinlock_types.h b/include/asm-arm/spinlock_types.h new file mode 100644 index 0000000000000..43e83f6d2ee53 --- /dev/null +++ b/include/asm-arm/spinlock_types.h @@ -0,0 +1,20 @@ +#ifndef __ASM_SPINLOCK_TYPES_H +#define __ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned int lock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile unsigned int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { 0 } + +#endif diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h index f9ff31f400369..23604350cdf45 100644 --- a/include/asm-i386/spinlock.h +++ b/include/asm-i386/spinlock.h @@ -7,46 +7,21 @@ #include <linux/config.h> #include <linux/compiler.h> -asmlinkage int printk(const char * fmt, ...) - __attribute__ ((format (printf, 1, 2))); - /* * Your basic SMP spinlocks, allowing only a single CPU anywhere - */ - -typedef struct { - volatile unsigned int slock; -#ifdef CONFIG_DEBUG_SPINLOCK - unsigned magic; -#endif -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; - -#define SPINLOCK_MAGIC 0xdead4ead - -#ifdef CONFIG_DEBUG_SPINLOCK -#define SPINLOCK_MAGIC_INIT , SPINLOCK_MAGIC -#else -#define SPINLOCK_MAGIC_INIT /* */ -#endif - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT } - -#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) - -/* + * * Simple spin lock operations. There are two variants, one clears IRQ's * on the local processor, one does not. * * We make no fairness assumptions. They have a cost. + * + * (the type definitions are in asm/spinlock_types.h) */ -#define spin_is_locked(x) (*(volatile signed char *)(&(x)->slock) <= 0) -#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) +#define __raw_spin_is_locked(x) \ + (*(volatile signed char *)(&(x)->slock) <= 0) -#define spin_lock_string \ +#define __raw_spin_lock_string \ "\n1:\t" \ "lock ; decb %0\n\t" \ "jns 3f\n" \ @@ -57,7 +32,7 @@ typedef struct { "jmp 1b\n" \ "3:\n\t" -#define spin_lock_string_flags \ +#define __raw_spin_lock_string_flags \ "\n1:\t" \ "lock ; decb %0\n\t" \ "jns 4f\n\t" \ @@ -73,86 +48,71 @@ typedef struct { "jmp 1b\n" \ "4:\n\t" +static inline void __raw_spin_lock(raw_spinlock_t *lock) +{ + __asm__ __volatile__( + __raw_spin_lock_string + :"=m" (lock->slock) : : "memory"); +} + +static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) +{ + __asm__ __volatile__( + __raw_spin_lock_string_flags + :"=m" (lock->slock) : "r" (flags) : "memory"); +} + +static inline int __raw_spin_trylock(raw_spinlock_t *lock) +{ + char oldval; + __asm__ __volatile__( + "xchgb %b0,%1" + :"=q" (oldval), "=m" (lock->slock) + :"0" (0) : "memory"); + return oldval > 0; +} + /* - * This works. Despite all the confusion. - * (except on PPro SMP or if we are using OOSTORE) + * __raw_spin_unlock based on writing $1 to the low byte. + * This method works. Despite all the confusion. + * (except on PPro SMP or if we are using OOSTORE, so we use xchgb there) * (PPro errata 66, 92) */ #if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE) -#define spin_unlock_string \ +#define __raw_spin_unlock_string \ "movb $1,%0" \ :"=m" (lock->slock) : : "memory" -static inline void _raw_spin_unlock(spinlock_t *lock) +static inline void __raw_spin_unlock(raw_spinlock_t *lock) { -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(lock->magic != SPINLOCK_MAGIC); - BUG_ON(!spin_is_locked(lock)); -#endif __asm__ __volatile__( - spin_unlock_string + __raw_spin_unlock_string ); } #else -#define spin_unlock_string \ +#define __raw_spin_unlock_string \ "xchgb %b0, %1" \ :"=q" (oldval), "=m" (lock->slock) \ :"0" (oldval) : "memory" -static inline void _raw_spin_unlock(spinlock_t *lock) +static inline void __raw_spin_unlock(raw_spinlock_t *lock) { char oldval = 1; -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(lock->magic != SPINLOCK_MAGIC); - BUG_ON(!spin_is_locked(lock)); -#endif - __asm__ __volatile__( - spin_unlock_string - ); -} -#endif - -static inline int _raw_spin_trylock(spinlock_t *lock) -{ - char oldval; __asm__ __volatile__( - "xchgb %b0,%1" - :"=q" (oldval), "=m" (lock->slock) - :"0" (0) : "memory"); - return oldval > 0; + __raw_spin_unlock_string + ); } -static inline void _raw_spin_lock(spinlock_t *lock) -{ -#ifdef CONFIG_DEBUG_SPINLOCK - if (unlikely(lock->magic != SPINLOCK_MAGIC)) { - printk("eip: %p\n", __builtin_return_address(0)); - BUG(); - } #endif - __asm__ __volatile__( - spin_lock_string - :"=m" (lock->slock) : : "memory"); -} -static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags) -{ -#ifdef CONFIG_DEBUG_SPINLOCK - if (unlikely(lock->magic != SPINLOCK_MAGIC)) { - printk("eip: %p\n", __builtin_return_address(0)); - BUG(); - } -#endif - __asm__ __volatile__( - spin_lock_string_flags - :"=m" (lock->slock) : "r" (flags) : "memory"); -} +#define __raw_spin_unlock_wait(lock) \ + do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0) /* * Read-write spinlocks, allowing multiple readers @@ -163,72 +123,41 @@ static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags) * can "mix" irq-safe locks - any writer needs to get a * irq-safe write-lock, but readers can get non-irqsafe * read-locks. + * + * On x86, we implement read-write locks as a 32-bit counter + * with the high bit (sign) being the "contended" bit. + * + * The inline assembly is non-obvious. Think about it. + * + * Changed to use the same technique as rw semaphores. See + * semaphore.h for details. -ben + * + * the helpers are in arch/i386/kernel/semaphore.c */ -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_DEBUG_SPINLOCK - unsigned magic; -#endif -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; - -#define RWLOCK_MAGIC 0xdeaf1eed - -#ifdef CONFIG_DEBUG_SPINLOCK -#define RWLOCK_MAGIC_INIT , RWLOCK_MAGIC -#else -#define RWLOCK_MAGIC_INIT /* */ -#endif - -#define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT } - -#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) /** * read_can_lock - would read_trylock() succeed? * @lock: the rwlock in question. */ -#define read_can_lock(x) ((int)(x)->lock > 0) +#define __raw_read_can_lock(x) ((int)(x)->lock > 0) /** * write_can_lock - would write_trylock() succeed? * @lock: the rwlock in question. */ -#define write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) +#define __raw_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) -/* - * On x86, we implement read-write locks as a 32-bit counter - * with the high bit (sign) being the "contended" bit. - * - * The inline assembly is non-obvious. Think about it. - * - * Changed to use the same technique as rw semaphores. See - * semaphore.h for details. -ben - */ -/* the spinlock helpers are in arch/i386/kernel/semaphore.c */ - -static inline void _raw_read_lock(rwlock_t *rw) +static inline void __raw_read_lock(raw_rwlock_t *rw) { -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(rw->magic != RWLOCK_MAGIC); -#endif __build_read_lock(rw, "__read_lock_failed"); } -static inline void _raw_write_lock(rwlock_t *rw) +static inline void __raw_write_lock(raw_rwlock_t *rw) { -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(rw->magic != RWLOCK_MAGIC); -#endif __build_write_lock(rw, "__write_lock_failed"); } -#define _raw_read_unlock(rw) asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory") -#define _raw_write_unlock(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory") - -static inline int _raw_read_trylock(rwlock_t *lock) +static inline int __raw_read_trylock(raw_rwlock_t *lock) { atomic_t *count = (atomic_t *)lock; atomic_dec(count); @@ -238,7 +167,7 @@ static inline int _raw_read_trylock(rwlock_t *lock) return 0; } -static inline int _raw_write_trylock(rwlock_t *lock) +static inline int __raw_write_trylock(raw_rwlock_t *lock) { atomic_t *count = (atomic_t *)lock; if (atomic_sub_and_test(RW_LOCK_BIAS, count)) @@ -247,4 +176,15 @@ static inline int _raw_write_trylock(rwlock_t *lock) return 0; } +static inline void __raw_read_unlock(raw_rwlock_t *rw) +{ + asm volatile("lock ; incl %0" :"=m" (rw->lock) : : "memory"); +} + +static inline void __raw_write_unlock(raw_rwlock_t *rw) +{ + asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ", %0" + : "=m" (rw->lock) : : "memory"); +} + #endif /* __ASM_SPINLOCK_H */ diff --git a/include/asm-i386/spinlock_types.h b/include/asm-i386/spinlock_types.h new file mode 100644 index 0000000000000..59efe849f351f --- /dev/null +++ b/include/asm-i386/spinlock_types.h @@ -0,0 +1,20 @@ +#ifndef __ASM_SPINLOCK_TYPES_H +#define __ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned int slock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 1 } + +typedef struct { + volatile unsigned int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } + +#endif diff --git a/include/asm-ia64/spinlock.h b/include/asm-ia64/spinlock.h index d2430aa0d49db..5b78611411c30 100644 --- a/include/asm-ia64/spinlock.h +++ b/include/asm-ia64/spinlock.h @@ -17,28 +17,20 @@ #include <asm/intrinsics.h> #include <asm/system.h> -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } -#define spin_lock_init(x) ((x)->lock = 0) +#define __raw_spin_lock_init(x) ((x)->lock = 0) #ifdef ASM_SUPPORTED /* * Try to get the lock. If we fail to get the lock, make a non-standard call to * ia64_spinlock_contention(). We do not use a normal call because that would force all - * callers of spin_lock() to be non-leaf routines. Instead, ia64_spinlock_contention() is - * carefully coded to touch only those registers that spin_lock() marks "clobbered". + * callers of __raw_spin_lock() to be non-leaf routines. Instead, ia64_spinlock_contention() is + * carefully coded to touch only those registers that __raw_spin_lock() marks "clobbered". */ #define IA64_SPINLOCK_CLOBBERS "ar.ccv", "ar.pfs", "p14", "p15", "r27", "r28", "r29", "r30", "b6", "memory" static inline void -_raw_spin_lock_flags (spinlock_t *lock, unsigned long flags) +__raw_spin_lock_flags (raw_spinlock_t *lock, unsigned long flags) { register volatile unsigned int *ptr asm ("r31") = &lock->lock; @@ -94,17 +86,17 @@ _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags) #endif } -#define _raw_spin_lock(lock) _raw_spin_lock_flags(lock, 0) +#define __raw_spin_lock(lock) __raw_spin_lock_flags(lock, 0) /* Unlock by doing an ordered store and releasing the cacheline with nta */ -static inline void _raw_spin_unlock(spinlock_t *x) { +static inline void __raw_spin_unlock(raw_spinlock_t *x) { barrier(); asm volatile ("st4.rel.nta [%0] = r0\n\t" :: "r"(x)); } #else /* !ASM_SUPPORTED */ -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) -# define _raw_spin_lock(x) \ +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) +# define __raw_spin_lock(x) \ do { \ __u32 *ia64_spinlock_ptr = (__u32 *) (x); \ __u64 ia64_spinlock_val; \ @@ -117,29 +109,20 @@ do { \ } while (ia64_spinlock_val); \ } \ } while (0) -#define _raw_spin_unlock(x) do { barrier(); ((spinlock_t *) x)->lock = 0; } while (0) +#define __raw_spin_unlock(x) do { barrier(); ((raw_spinlock_t *) x)->lock = 0; } while (0) #endif /* !ASM_SUPPORTED */ -#define spin_is_locked(x) ((x)->lock != 0) -#define _raw_spin_trylock(x) (cmpxchg_acq(&(x)->lock, 0, 1) == 0) -#define spin_unlock_wait(x) do { barrier(); } while ((x)->lock) - -typedef struct { - volatile unsigned int read_counter : 24; - volatile unsigned int write_lock : 8; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#define __raw_spin_is_locked(x) ((x)->lock != 0) +#define __raw_spin_trylock(x) (cmpxchg_acq(&(x)->lock, 0, 1) == 0) +#define __raw_spin_unlock_wait(lock) \ + do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0) -#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) -#define read_can_lock(rw) (*(volatile int *)(rw) >= 0) -#define write_can_lock(rw) (*(volatile int *)(rw) == 0) +#define __raw_read_can_lock(rw) (*(volatile int *)(rw) >= 0) +#define __raw_write_can_lock(rw) (*(volatile int *)(rw) == 0) -#define _raw_read_lock(rw) \ +#define __raw_read_lock(rw) \ do { \ - rwlock_t *__read_lock_ptr = (rw); \ + raw_rwlock_t *__read_lock_ptr = (rw); \ \ while (unlikely(ia64_fetchadd(1, (int *) __read_lock_ptr, acq) < 0)) { \ ia64_fetchadd(-1, (int *) __read_lock_ptr, rel); \ @@ -148,14 +131,14 @@ do { \ } \ } while (0) -#define _raw_read_unlock(rw) \ +#define __raw_read_unlock(rw) \ do { \ - rwlock_t *__read_lock_ptr = (rw); \ + raw_rwlock_t *__read_lock_ptr = (rw); \ ia64_fetchadd(-1, (int *) __read_lock_ptr, rel); \ } while (0) #ifdef ASM_SUPPORTED -#define _raw_write_lock(rw) \ +#define __raw_write_lock(rw) \ do { \ __asm__ __volatile__ ( \ "mov ar.ccv = r0\n" \ @@ -170,7 +153,7 @@ do { \ :: "r"(rw) : "ar.ccv", "p7", "r2", "r29", "memory"); \ } while(0) -#define _raw_write_trylock(rw) \ +#define __raw_write_trylock(rw) \ ({ \ register long result; \ \ @@ -182,7 +165,7 @@ do { \ (result == 0); \ }) -static inline void _raw_write_unlock(rwlock_t *x) +static inline void __raw_write_unlock(raw_rwlock_t *x) { u8 *y = (u8 *)x; barrier(); @@ -191,7 +174,7 @@ static inline void _raw_write_unlock(rwlock_t *x) #else /* !ASM_SUPPORTED */ -#define _raw_write_lock(l) \ +#define __raw_write_lock(l) \ ({ \ __u64 ia64_val, ia64_set_val = ia64_dep_mi(-1, 0, 31, 1); \ __u32 *ia64_write_lock_ptr = (__u32 *) (l); \ @@ -202,7 +185,7 @@ static inline void _raw_write_unlock(rwlock_t *x) } while (ia64_val); \ }) -#define _raw_write_trylock(rw) \ +#define __raw_write_trylock(rw) \ ({ \ __u64 ia64_val; \ __u64 ia64_set_val = ia64_dep_mi(-1, 0, 31,1); \ @@ -210,7 +193,7 @@ static inline void _raw_write_unlock(rwlock_t *x) (ia64_val == 0); \ }) -static inline void _raw_write_unlock(rwlock_t *x) +static inline void __raw_write_unlock(raw_rwlock_t *x) { barrier(); x->write_lock = 0; @@ -218,6 +201,6 @@ static inline void _raw_write_unlock(rwlock_t *x) #endif /* !ASM_SUPPORTED */ -#define _raw_read_trylock(lock) generic_raw_read_trylock(lock) +#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) #endif /* _ASM_IA64_SPINLOCK_H */ diff --git a/include/asm-ia64/spinlock_types.h b/include/asm-ia64/spinlock_types.h new file mode 100644 index 0000000000000..474e46f1ab4a0 --- /dev/null +++ b/include/asm-ia64/spinlock_types.h @@ -0,0 +1,21 @@ +#ifndef _ASM_IA64_SPINLOCK_TYPES_H +#define _ASM_IA64_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned int lock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile unsigned int read_counter : 31; + volatile unsigned int write_lock : 1; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { 0, 0 } + +#endif diff --git a/include/asm-m32r/spinlock.h b/include/asm-m32r/spinlock.h index 6608d8371c508..7de7def28da97 100644 --- a/include/asm-m32r/spinlock.h +++ b/include/asm-m32r/spinlock.h @@ -14,57 +14,30 @@ #include <asm/atomic.h> #include <asm/page.h> -extern int printk(const char * fmt, ...) - __attribute__ ((format (printf, 1, 2))); - -#define RW_LOCK_BIAS 0x01000000 -#define RW_LOCK_BIAS_STR "0x01000000" - /* * Your basic SMP spinlocks, allowing only a single CPU anywhere - */ - -typedef struct { - volatile int slock; -#ifdef CONFIG_DEBUG_SPINLOCK - unsigned magic; -#endif -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; - -#define SPINLOCK_MAGIC 0xdead4ead - -#ifdef CONFIG_DEBUG_SPINLOCK -#define SPINLOCK_MAGIC_INIT , SPINLOCK_MAGIC -#else -#define SPINLOCK_MAGIC_INIT /* */ -#endif - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT } - -#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) - -/* + * + * (the type definitions are in asm/spinlock_types.h) + * * Simple spin lock operations. There are two variants, one clears IRQ's * on the local processor, one does not. * * We make no fairness assumptions. They have a cost. */ -#define spin_is_locked(x) (*(volatile int *)(&(x)->slock) <= 0) -#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) +#define __raw_spin_is_locked(x) (*(volatile int *)(&(x)->slock) <= 0) +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) +#define __raw_spin_unlock_wait(x) \ + do { cpu_relax(); } while (__raw_spin_is_locked(x)) /** - * _raw_spin_trylock - Try spin lock and return a result + * __raw_spin_trylock - Try spin lock and return a result * @lock: Pointer to the lock variable * - * _raw_spin_trylock() tries to get the lock and returns a result. + * __raw_spin_trylock() tries to get the lock and returns a result. * On the m32r, the result value is 1 (= Success) or 0 (= Failure). */ -static inline int _raw_spin_trylock(spinlock_t *lock) +static inline int __raw_spin_trylock(raw_spinlock_t *lock) { int oldval; unsigned long tmp1, tmp2; @@ -78,7 +51,7 @@ static inline int _raw_spin_trylock(spinlock_t *lock) * } */ __asm__ __volatile__ ( - "# spin_trylock \n\t" + "# __raw_spin_trylock \n\t" "ldi %1, #0; \n\t" "mvfc %2, psw; \n\t" "clrpsw #0x40 -> nop; \n\t" @@ -97,16 +70,10 @@ static inline int _raw_spin_trylock(spinlock_t *lock) return (oldval > 0); } -static inline void _raw_spin_lock(spinlock_t *lock) +static inline void __raw_spin_lock(raw_spinlock_t *lock) { unsigned long tmp0, tmp1; -#ifdef CONFIG_DEBUG_SPINLOCK - if (unlikely(lock->magic != SPINLOCK_MAGIC)) { - printk("pc: %p\n", __builtin_return_address(0)); - BUG(); - } -#endif /* * lock->slock : =1 : unlock * : <=0 : lock @@ -118,7 +85,7 @@ static inline void _raw_spin_lock(spinlock_t *lock) * } */ __asm__ __volatile__ ( - "# spin_lock \n\t" + "# __raw_spin_lock \n\t" ".fillinsn \n" "1: \n\t" "mvfc %1, psw; \n\t" @@ -145,12 +112,8 @@ static inline void _raw_spin_lock(spinlock_t *lock) ); } -static inline void _raw_spin_unlock(spinlock_t *lock) +static inline void __raw_spin_unlock(raw_spinlock_t *lock) { -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(lock->magic != SPINLOCK_MAGIC); - BUG_ON(!spin_is_locked(lock)); -#endif mb(); lock->slock = 1; } @@ -164,59 +127,32 @@ static inline void _raw_spin_unlock(spinlock_t *lock) * can "mix" irq-safe locks - any writer needs to get a * irq-safe write-lock, but readers can get non-irqsafe * read-locks. + * + * On x86, we implement read-write locks as a 32-bit counter + * with the high bit (sign) being the "contended" bit. + * + * The inline assembly is non-obvious. Think about it. + * + * Changed to use the same technique as rw semaphores. See + * semaphore.h for details. -ben */ -typedef struct { - volatile int lock; -#ifdef CONFIG_DEBUG_SPINLOCK - unsigned magic; -#endif -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; - -#define RWLOCK_MAGIC 0xdeaf1eed - -#ifdef CONFIG_DEBUG_SPINLOCK -#define RWLOCK_MAGIC_INIT , RWLOCK_MAGIC -#else -#define RWLOCK_MAGIC_INIT /* */ -#endif - -#define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT } - -#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) /** * read_can_lock - would read_trylock() succeed? * @lock: the rwlock in question. */ -#define read_can_lock(x) ((int)(x)->lock > 0) +#define __raw_read_can_lock(x) ((int)(x)->lock > 0) /** * write_can_lock - would write_trylock() succeed? * @lock: the rwlock in question. */ -#define write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) - -/* - * On x86, we implement read-write locks as a 32-bit counter - * with the high bit (sign) being the "contended" bit. - * - * The inline assembly is non-obvious. Think about it. - * - * Changed to use the same technique as rw semaphores. See - * semaphore.h for details. -ben - */ -/* the spinlock helpers are in arch/i386/kernel/semaphore.c */ +#define __raw_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) -static inline void _raw_read_lock(rwlock_t *rw) +static inline void __raw_read_lock(raw_rwlock_t *rw) { unsigned long tmp0, tmp1; -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(rw->magic != RWLOCK_MAGIC); -#endif /* * rw->lock : >0 : unlock * : <=0 : lock @@ -264,13 +200,10 @@ static inline void _raw_read_lock(rwlock_t *rw) ); } -static inline void _raw_write_lock(rwlock_t *rw) +static inline void __raw_write_lock(raw_rwlock_t *rw) { unsigned long tmp0, tmp1, tmp2; -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(rw->magic != RWLOCK_MAGIC); -#endif /* * rw->lock : =RW_LOCK_BIAS_STR : unlock * : !=RW_LOCK_BIAS_STR : lock @@ -320,7 +253,7 @@ static inline void _raw_write_lock(rwlock_t *rw) ); } -static inline void _raw_read_unlock(rwlock_t *rw) +static inline void __raw_read_unlock(raw_rwlock_t *rw) { unsigned long tmp0, tmp1; @@ -342,7 +275,7 @@ static inline void _raw_read_unlock(rwlock_t *rw) ); } -static inline void _raw_write_unlock(rwlock_t *rw) +static inline void __raw_write_unlock(raw_rwlock_t *rw) { unsigned long tmp0, tmp1, tmp2; @@ -366,9 +299,9 @@ static inline void _raw_write_unlock(rwlock_t *rw) ); } -#define _raw_read_trylock(lock) generic_raw_read_trylock(lock) +#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) -static inline int _raw_write_trylock(rwlock_t *lock) +static inline int __raw_write_trylock(raw_rwlock_t *lock) { atomic_t *count = (atomic_t *)lock; if (atomic_sub_and_test(RW_LOCK_BIAS, count)) diff --git a/include/asm-m32r/spinlock_types.h b/include/asm-m32r/spinlock_types.h new file mode 100644 index 0000000000000..7e9941c45f402 --- /dev/null +++ b/include/asm-m32r/spinlock_types.h @@ -0,0 +1,23 @@ +#ifndef _ASM_M32R_SPINLOCK_TYPES_H +#define _ASM_M32R_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile int slock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 1 } + +typedef struct { + volatile int lock; +} raw_rwlock_t; + +#define RW_LOCK_BIAS 0x01000000 +#define RW_LOCK_BIAS_STR "0x01000000" + +#define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } + +#endif diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h index 114d3eb98a6aa..4d0135b111567 100644 --- a/include/asm-mips/spinlock.h +++ b/include/asm-mips/spinlock.h @@ -16,20 +16,10 @@ * Your basic SMP spinlocks, allowing only a single CPU anywhere */ -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } - -#define spin_lock_init(x) do { (x)->lock = 0; } while(0) - -#define spin_is_locked(x) ((x)->lock != 0) -#define spin_unlock_wait(x) do { barrier(); } while ((x)->lock) -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) +#define __raw_spin_is_locked(x) ((x)->lock != 0) +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) +#define __raw_spin_unlock_wait(x) \ + do { cpu_relax(); } while ((x)->lock) /* * Simple spin lock operations. There are two variants, one clears IRQ's @@ -38,13 +28,13 @@ typedef struct { * We make no fairness assumptions. They have a cost. */ -static inline void _raw_spin_lock(spinlock_t *lock) +static inline void __raw_spin_lock(raw_spinlock_t *lock) { unsigned int tmp; if (R10000_LLSC_WAR) { __asm__ __volatile__( - " .set noreorder # _raw_spin_lock \n" + " .set noreorder # __raw_spin_lock \n" "1: ll %1, %2 \n" " bnez %1, 1b \n" " li %1, 1 \n" @@ -58,7 +48,7 @@ static inline void _raw_spin_lock(spinlock_t *lock) : "memory"); } else { __asm__ __volatile__( - " .set noreorder # _raw_spin_lock \n" + " .set noreorder # __raw_spin_lock \n" "1: ll %1, %2 \n" " bnez %1, 1b \n" " li %1, 1 \n" @@ -72,10 +62,10 @@ static inline void _raw_spin_lock(spinlock_t *lock) } } -static inline void _raw_spin_unlock(spinlock_t *lock) +static inline void __raw_spin_unlock(raw_spinlock_t *lock) { __asm__ __volatile__( - " .set noreorder # _raw_spin_unlock \n" + " .set noreorder # __raw_spin_unlock \n" " sync \n" " sw $0, %0 \n" " .set\treorder \n" @@ -84,13 +74,13 @@ static inline void _raw_spin_unlock(spinlock_t *lock) : "memory"); } -static inline unsigned int _raw_spin_trylock(spinlock_t *lock) +static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock) { unsigned int temp, res; if (R10000_LLSC_WAR) { __asm__ __volatile__( - " .set noreorder # _raw_spin_trylock \n" + " .set noreorder # __raw_spin_trylock \n" "1: ll %0, %3 \n" " ori %2, %0, 1 \n" " sc %2, %1 \n" @@ -104,7 +94,7 @@ static inline unsigned int _raw_spin_trylock(spinlock_t *lock) : "memory"); } else { __asm__ __volatile__( - " .set noreorder # _raw_spin_trylock \n" + " .set noreorder # __raw_spin_trylock \n" "1: ll %0, %3 \n" " ori %2, %0, 1 \n" " sc %2, %1 \n" @@ -129,24 +119,13 @@ static inline unsigned int _raw_spin_trylock(spinlock_t *lock) * read-locks. */ -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; - -#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } - -#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) - -static inline void _raw_read_lock(rwlock_t *rw) +static inline void __raw_read_lock(raw_rwlock_t *rw) { unsigned int tmp; if (R10000_LLSC_WAR) { __asm__ __volatile__( - " .set noreorder # _raw_read_lock \n" + " .set noreorder # __raw_read_lock \n" "1: ll %1, %2 \n" " bltz %1, 1b \n" " addu %1, 1 \n" @@ -160,7 +139,7 @@ static inline void _raw_read_lock(rwlock_t *rw) : "memory"); } else { __asm__ __volatile__( - " .set noreorder # _raw_read_lock \n" + " .set noreorder # __raw_read_lock \n" "1: ll %1, %2 \n" " bltz %1, 1b \n" " addu %1, 1 \n" @@ -177,13 +156,13 @@ static inline void _raw_read_lock(rwlock_t *rw) /* Note the use of sub, not subu which will make the kernel die with an overflow exception if we ever try to unlock an rwlock that is already unlocked or is being held by a writer. */ -static inline void _raw_read_unlock(rwlock_t *rw) +static inline void __raw_read_unlock(raw_rwlock_t *rw) { unsigned int tmp; if (R10000_LLSC_WAR) { __asm__ __volatile__( - "1: ll %1, %2 # _raw_read_unlock \n" + "1: ll %1, %2 # __raw_read_unlock \n" " sub %1, 1 \n" " sc %1, %0 \n" " beqzl %1, 1b \n" @@ -193,7 +172,7 @@ static inline void _raw_read_unlock(rwlock_t *rw) : "memory"); } else { __asm__ __volatile__( - " .set noreorder # _raw_read_unlock \n" + " .set noreorder # __raw_read_unlock \n" "1: ll %1, %2 \n" " sub %1, 1 \n" " sc %1, %0 \n" @@ -206,13 +185,13 @@ static inline void _raw_read_unlock(rwlock_t *rw) } } -static inline void _raw_write_lock(rwlock_t *rw) +static inline void __raw_write_lock(raw_rwlock_t *rw) { unsigned int tmp; if (R10000_LLSC_WAR) { __asm__ __volatile__( - " .set noreorder # _raw_write_lock \n" + " .set noreorder # __raw_write_lock \n" "1: ll %1, %2 \n" " bnez %1, 1b \n" " lui %1, 0x8000 \n" @@ -226,7 +205,7 @@ static inline void _raw_write_lock(rwlock_t *rw) : "memory"); } else { __asm__ __volatile__( - " .set noreorder # _raw_write_lock \n" + " .set noreorder # __raw_write_lock \n" "1: ll %1, %2 \n" " bnez %1, 1b \n" " lui %1, 0x8000 \n" @@ -241,26 +220,26 @@ static inline void _raw_write_lock(rwlock_t *rw) } } -static inline void _raw_write_unlock(rwlock_t *rw) +static inline void __raw_write_unlock(raw_rwlock_t *rw) { __asm__ __volatile__( - " sync # _raw_write_unlock \n" + " sync # __raw_write_unlock \n" " sw $0, %0 \n" : "=m" (rw->lock) : "m" (rw->lock) : "memory"); } -#define _raw_read_trylock(lock) generic_raw_read_trylock(lock) +#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) -static inline int _raw_write_trylock(rwlock_t *rw) +static inline int __raw_write_trylock(raw_rwlock_t *rw) { unsigned int tmp; int ret; if (R10000_LLSC_WAR) { __asm__ __volatile__( - " .set noreorder # _raw_write_trylock \n" + " .set noreorder # __raw_write_trylock \n" " li %2, 0 \n" "1: ll %1, %3 \n" " bnez %1, 2f \n" @@ -277,7 +256,7 @@ static inline int _raw_write_trylock(rwlock_t *rw) : "memory"); } else { __asm__ __volatile__( - " .set noreorder # _raw_write_trylock \n" + " .set noreorder # __raw_write_trylock \n" " li %2, 0 \n" "1: ll %1, %3 \n" " bnez %1, 2f \n" diff --git a/include/asm-mips/spinlock_types.h b/include/asm-mips/spinlock_types.h new file mode 100644 index 0000000000000..ce26c5048b154 --- /dev/null +++ b/include/asm-mips/spinlock_types.h @@ -0,0 +1,20 @@ +#ifndef _ASM_SPINLOCK_TYPES_H +#define _ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned int lock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile unsigned int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { 0 } + +#endif diff --git a/include/asm-parisc/atomic.h b/include/asm-parisc/atomic.h index e24f7579adb0d..048a2c7fd0c0a 100644 --- a/include/asm-parisc/atomic.h +++ b/include/asm-parisc/atomic.h @@ -24,19 +24,19 @@ # define ATOMIC_HASH_SIZE 4 # define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ])) -extern spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned; +extern raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned; -/* Can't use _raw_spin_lock_irq because of #include problems, so +/* Can't use raw_spin_lock_irq because of #include problems, so * this is the substitute */ #define _atomic_spin_lock_irqsave(l,f) do { \ - spinlock_t *s = ATOMIC_HASH(l); \ + raw_spinlock_t *s = ATOMIC_HASH(l); \ local_irq_save(f); \ - _raw_spin_lock(s); \ + __raw_spin_lock(s); \ } while(0) #define _atomic_spin_unlock_irqrestore(l,f) do { \ - spinlock_t *s = ATOMIC_HASH(l); \ - _raw_spin_unlock(s); \ + raw_spinlock_t *s = ATOMIC_HASH(l); \ + __raw_spin_unlock(s); \ local_irq_restore(f); \ } while(0) diff --git a/include/asm-parisc/bitops.h b/include/asm-parisc/bitops.h index 928e5ef850bd2..af7db694b22d3 100644 --- a/include/asm-parisc/bitops.h +++ b/include/asm-parisc/bitops.h @@ -2,7 +2,7 @@ #define _PARISC_BITOPS_H #include <linux/compiler.h> -#include <asm/system.h> +#include <asm/spinlock.h> #include <asm/byteorder.h> #include <asm/atomic.h> diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h index 06732719d927f..aa592d8c0e396 100644 --- a/include/asm-parisc/cacheflush.h +++ b/include/asm-parisc/cacheflush.h @@ -3,6 +3,7 @@ #include <linux/config.h> #include <linux/mm.h> +#include <asm/cache.h> /* for flush_user_dcache_range_asm() proto */ /* The usual comment is "Caches aren't brain-dead on the <architecture>". * Unfortunately, that doesn't apply to PA-RISC. */ diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h index 0b61f51d84670..a9dfadd05658e 100644 --- a/include/asm-parisc/processor.h +++ b/include/asm-parisc/processor.h @@ -11,6 +11,7 @@ #ifndef __ASSEMBLY__ #include <linux/config.h> #include <linux/threads.h> +#include <linux/spinlock_types.h> #include <asm/hardware.h> #include <asm/page.h> diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h index 679ea1c651efe..43eaa6e742e06 100644 --- a/include/asm-parisc/spinlock.h +++ b/include/asm-parisc/spinlock.h @@ -2,30 +2,25 @@ #define __ASM_SPINLOCK_H #include <asm/system.h> +#include <asm/processor.h> +#include <asm/spinlock_types.h> /* Note that PA-RISC has to use `1' to mean unlocked and `0' to mean locked * since it only has load-and-zero. Moreover, at least on some PA processors, * the semaphore address has to be 16-byte aligned. */ -#ifndef CONFIG_DEBUG_SPINLOCK - -#define __SPIN_LOCK_UNLOCKED { { 1, 1, 1, 1 } } -#undef SPIN_LOCK_UNLOCKED -#define SPIN_LOCK_UNLOCKED (spinlock_t) __SPIN_LOCK_UNLOCKED - -#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) - -static inline int spin_is_locked(spinlock_t *x) +static inline int __raw_spin_is_locked(raw_spinlock_t *x) { volatile unsigned int *a = __ldcw_align(x); return *a == 0; } -#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) +#define __raw_spin_unlock_wait(x) \ + do { cpu_relax(); } while (__raw_spin_is_locked(x)) -static inline void _raw_spin_lock(spinlock_t *x) +static inline void __raw_spin_lock(raw_spinlock_t *x) { volatile unsigned int *a; @@ -36,7 +31,7 @@ static inline void _raw_spin_lock(spinlock_t *x) mb(); } -static inline void _raw_spin_unlock(spinlock_t *x) +static inline void __raw_spin_unlock(raw_spinlock_t *x) { volatile unsigned int *a; mb(); @@ -45,7 +40,7 @@ static inline void _raw_spin_unlock(spinlock_t *x) mb(); } -static inline int _raw_spin_trylock(spinlock_t *x) +static inline int __raw_spin_trylock(raw_spinlock_t *x) { volatile unsigned int *a; int ret; @@ -57,131 +52,38 @@ static inline int _raw_spin_trylock(spinlock_t *x) return ret; } - -#define spin_lock_own(LOCK, LOCATION) ((void)0) - -#else /* !(CONFIG_DEBUG_SPINLOCK) */ - -#define SPINLOCK_MAGIC 0x1D244B3C - -#define __SPIN_LOCK_UNLOCKED { { 1, 1, 1, 1 }, SPINLOCK_MAGIC, 10, __FILE__ , NULL, 0, -1, NULL, NULL } -#undef SPIN_LOCK_UNLOCKED -#define SPIN_LOCK_UNLOCKED (spinlock_t) __SPIN_LOCK_UNLOCKED - -#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) - -#define CHECK_LOCK(x) \ - do { \ - if (unlikely((x)->magic != SPINLOCK_MAGIC)) { \ - printk(KERN_ERR "%s:%d: spin_is_locked" \ - " on uninitialized spinlock %p.\n", \ - __FILE__, __LINE__, (x)); \ - } \ - } while(0) - -#define spin_is_locked(x) \ - ({ \ - CHECK_LOCK(x); \ - volatile unsigned int *a = __ldcw_align(x); \ - if (unlikely((*a == 0) && (x)->babble)) { \ - (x)->babble--; \ - printk("KERN_WARNING \ - %s:%d: spin_is_locked(%s/%p) already" \ - " locked by %s:%d in %s at %p(%d)\n", \ - __FILE__,__LINE__, (x)->module, (x), \ - (x)->bfile, (x)->bline, (x)->task->comm,\ - (x)->previous, (x)->oncpu); \ - } \ - *a == 0; \ - }) - -#define spin_unlock_wait(x) \ - do { \ - CHECK_LOCK(x); \ - volatile unsigned int *a = __ldcw_align(x); \ - if (unlikely((*a == 0) && (x)->babble)) { \ - (x)->babble--; \ - printk("KERN_WARNING \ - %s:%d: spin_unlock_wait(%s/%p)" \ - " owned by %s:%d in %s at %p(%d)\n", \ - __FILE__,__LINE__, (x)->module, (x), \ - (x)->bfile, (x)->bline, (x)->task->comm,\ - (x)->previous, (x)->oncpu); \ - } \ - barrier(); \ - } while (*((volatile unsigned char *)(__ldcw_align(x))) == 0) - -extern void _dbg_spin_lock(spinlock_t *lock, const char *base_file, int line_no); -extern void _dbg_spin_unlock(spinlock_t *lock, const char *, int); -extern int _dbg_spin_trylock(spinlock_t * lock, const char *, int); - -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) - -#define _raw_spin_unlock(lock) _dbg_spin_unlock(lock, __FILE__, __LINE__) -#define _raw_spin_lock(lock) _dbg_spin_lock(lock, __FILE__, __LINE__) -#define _raw_spin_trylock(lock) _dbg_spin_trylock(lock, __FILE__, __LINE__) - -/* just in case we need it */ -#define spin_lock_own(LOCK, LOCATION) \ -do { \ - volatile unsigned int *a = __ldcw_align(LOCK); \ - if (!((*a == 0) && ((LOCK)->oncpu == smp_processor_id()))) \ - printk("KERN_WARNING \ - %s: called on %d from %p but lock %s on %d\n", \ - LOCATION, smp_processor_id(), \ - __builtin_return_address(0), \ - (*a == 0) ? "taken" : "freed", (LOCK)->on_cpu); \ -} while (0) - -#endif /* !(CONFIG_DEBUG_SPINLOCK) */ /* * Read-write spinlocks, allowing multiple readers * but only one writer. */ -typedef struct { - spinlock_t lock; - volatile int counter; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; - -#define RW_LOCK_UNLOCKED (rwlock_t) { __SPIN_LOCK_UNLOCKED, 0 } - -#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while (0) -#define _raw_read_trylock(lock) generic_raw_read_trylock(lock) +#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) /* read_lock, read_unlock are pretty straightforward. Of course it somehow * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */ -#ifdef CONFIG_DEBUG_RWLOCK -extern void _dbg_read_lock(rwlock_t * rw, const char *bfile, int bline); -#define _raw_read_lock(rw) _dbg_read_lock(rw, __FILE__, __LINE__) -#else -static __inline__ void _raw_read_lock(rwlock_t *rw) +static __inline__ void __raw_read_lock(raw_rwlock_t *rw) { unsigned long flags; local_irq_save(flags); - _raw_spin_lock(&rw->lock); + __raw_spin_lock(&rw->lock); rw->counter++; - _raw_spin_unlock(&rw->lock); + __raw_spin_unlock(&rw->lock); local_irq_restore(flags); } -#endif /* CONFIG_DEBUG_RWLOCK */ -static __inline__ void _raw_read_unlock(rwlock_t *rw) +static __inline__ void __raw_read_unlock(raw_rwlock_t *rw) { unsigned long flags; local_irq_save(flags); - _raw_spin_lock(&rw->lock); + __raw_spin_lock(&rw->lock); rw->counter--; - _raw_spin_unlock(&rw->lock); + __raw_spin_unlock(&rw->lock); local_irq_restore(flags); } @@ -194,20 +96,17 @@ static __inline__ void _raw_read_unlock(rwlock_t *rw) * writers) in interrupt handlers someone fucked up and we'd dead-lock * sooner or later anyway. prumpf */ -#ifdef CONFIG_DEBUG_RWLOCK -extern void _dbg_write_lock(rwlock_t * rw, const char *bfile, int bline); -#define _raw_write_lock(rw) _dbg_write_lock(rw, __FILE__, __LINE__) -#else -static __inline__ void _raw_write_lock(rwlock_t *rw) +static __inline__ void __raw_write_lock(raw_rwlock_t *rw) { retry: - _raw_spin_lock(&rw->lock); + __raw_spin_lock(&rw->lock); if(rw->counter != 0) { /* this basically never happens */ - _raw_spin_unlock(&rw->lock); + __raw_spin_unlock(&rw->lock); - while(rw->counter != 0); + while (rw->counter != 0) + cpu_relax(); goto retry; } @@ -215,26 +114,21 @@ static __inline__ void _raw_write_lock(rwlock_t *rw) /* got it. now leave without unlocking */ rw->counter = -1; /* remember we are locked */ } -#endif /* CONFIG_DEBUG_RWLOCK */ /* write_unlock is absolutely trivial - we don't have to wait for anything */ -static __inline__ void _raw_write_unlock(rwlock_t *rw) +static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) { rw->counter = 0; - _raw_spin_unlock(&rw->lock); + __raw_spin_unlock(&rw->lock); } -#ifdef CONFIG_DEBUG_RWLOCK -extern int _dbg_write_trylock(rwlock_t * rw, const char *bfile, int bline); -#define _raw_write_trylock(rw) _dbg_write_trylock(rw, __FILE__, __LINE__) -#else -static __inline__ int _raw_write_trylock(rwlock_t *rw) +static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) { - _raw_spin_lock(&rw->lock); + __raw_spin_lock(&rw->lock); if (rw->counter != 0) { /* this basically never happens */ - _raw_spin_unlock(&rw->lock); + __raw_spin_unlock(&rw->lock); return 0; } @@ -243,14 +137,13 @@ static __inline__ int _raw_write_trylock(rwlock_t *rw) rw->counter = -1; /* remember we are locked */ return 1; } -#endif /* CONFIG_DEBUG_RWLOCK */ -static __inline__ int is_read_locked(rwlock_t *rw) +static __inline__ int __raw_is_read_locked(raw_rwlock_t *rw) { return rw->counter > 0; } -static __inline__ int is_write_locked(rwlock_t *rw) +static __inline__ int __raw_is_write_locked(raw_rwlock_t *rw) { return rw->counter < 0; } diff --git a/include/asm-parisc/spinlock_types.h b/include/asm-parisc/spinlock_types.h new file mode 100644 index 0000000000000..785bba822fbfa --- /dev/null +++ b/include/asm-parisc/spinlock_types.h @@ -0,0 +1,21 @@ +#ifndef __ASM_SPINLOCK_TYPES_H +#define __ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned int lock[4]; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { { 1, 1, 1, 1 } } + +typedef struct { + raw_spinlock_t lock; + volatile int counter; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { __RAW_SPIN_LOCK_UNLOCKED, 0 } + +#endif diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h index 81c543339036c..26ff844a21c18 100644 --- a/include/asm-parisc/system.h +++ b/include/asm-parisc/system.h @@ -160,29 +160,7 @@ static inline void set_eiem(unsigned long val) }) #ifdef CONFIG_SMP -/* - * Your basic SMP spinlocks, allowing only a single CPU anywhere - */ - -typedef struct { - volatile unsigned int lock[4]; -#ifdef CONFIG_DEBUG_SPINLOCK - unsigned long magic; - volatile unsigned int babble; - const char *module; - char *bfile; - int bline; - int oncpu; - void *previous; - struct task_struct * task; -#endif -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; - -#define __lock_aligned __attribute__((__section__(".data.lock_aligned"))) - +# define __lock_aligned __attribute__((__section__(".data.lock_aligned"))) #endif #define KERNEL_START (0x10100000 - 0x1000) diff --git a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h index 909199aae1047..20edcf2a6e0ce 100644 --- a/include/asm-ppc/spinlock.h +++ b/include/asm-ppc/spinlock.h @@ -5,41 +5,21 @@ /* * Simple spin lock operations. + * + * (the type definitions are in asm/raw_spinlock_types.h) */ -typedef struct { - volatile unsigned long lock; -#ifdef CONFIG_DEBUG_SPINLOCK - volatile unsigned long owner_pc; - volatile unsigned long owner_cpu; -#endif -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; - -#ifdef __KERNEL__ -#ifdef CONFIG_DEBUG_SPINLOCK -#define SPINLOCK_DEBUG_INIT , 0, 0 -#else -#define SPINLOCK_DEBUG_INIT /* */ -#endif - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 SPINLOCK_DEBUG_INIT } - -#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) -#define spin_is_locked(x) ((x)->lock != 0) -#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) - -#ifndef CONFIG_DEBUG_SPINLOCK - -static inline void _raw_spin_lock(spinlock_t *lock) +#define __raw_spin_is_locked(x) ((x)->lock != 0) +#define __raw_spin_unlock_wait(lock) \ + do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0) +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) + +static inline void __raw_spin_lock(raw_spinlock_t *lock) { unsigned long tmp; __asm__ __volatile__( - "b 1f # spin_lock\n\ + "b 1f # __raw_spin_lock\n\ 2: lwzx %0,0,%1\n\ cmpwi 0,%0,0\n\ bne+ 2b\n\ @@ -55,21 +35,13 @@ static inline void _raw_spin_lock(spinlock_t *lock) : "cr0", "memory"); } -static inline void _raw_spin_unlock(spinlock_t *lock) +static inline void __raw_spin_unlock(raw_spinlock_t *lock) { - __asm__ __volatile__("eieio # spin_unlock": : :"memory"); + __asm__ __volatile__("eieio # __raw_spin_unlock": : :"memory"); lock->lock = 0; } -#define _raw_spin_trylock(l) (!test_and_set_bit(0,&(l)->lock)) - -#else - -extern void _raw_spin_lock(spinlock_t *lock); -extern void _raw_spin_unlock(spinlock_t *lock); -extern int _raw_spin_trylock(spinlock_t *lock); - -#endif +#define __raw_spin_trylock(l) (!test_and_set_bit(0,&(l)->lock)) /* * Read-write spinlocks, allowing multiple readers @@ -81,22 +53,11 @@ extern int _raw_spin_trylock(spinlock_t *lock); * irq-safe write-lock, but readers can get non-irqsafe * read-locks. */ -typedef struct { - volatile signed int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } -#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) +#define __raw_read_can_lock(rw) ((rw)->lock >= 0) +#define __raw_write_can_lock(rw) (!(rw)->lock) -#define read_can_lock(rw) ((rw)->lock >= 0) -#define write_can_lock(rw) (!(rw)->lock) - -#ifndef CONFIG_DEBUG_SPINLOCK - -static __inline__ int _raw_read_trylock(rwlock_t *rw) +static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) { signed int tmp; @@ -116,7 +77,7 @@ static __inline__ int _raw_read_trylock(rwlock_t *rw) return tmp > 0; } -static __inline__ void _raw_read_lock(rwlock_t *rw) +static __inline__ void __raw_read_lock(raw_rwlock_t *rw) { signed int tmp; @@ -137,7 +98,7 @@ static __inline__ void _raw_read_lock(rwlock_t *rw) : "cr0", "memory"); } -static __inline__ void _raw_read_unlock(rwlock_t *rw) +static __inline__ void __raw_read_unlock(raw_rwlock_t *rw) { signed int tmp; @@ -153,7 +114,7 @@ static __inline__ void _raw_read_unlock(rwlock_t *rw) : "cr0", "memory"); } -static __inline__ int _raw_write_trylock(rwlock_t *rw) +static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) { signed int tmp; @@ -173,7 +134,7 @@ static __inline__ int _raw_write_trylock(rwlock_t *rw) return tmp == 0; } -static __inline__ void _raw_write_lock(rwlock_t *rw) +static __inline__ void __raw_write_lock(raw_rwlock_t *rw) { signed int tmp; @@ -194,22 +155,10 @@ static __inline__ void _raw_write_lock(rwlock_t *rw) : "cr0", "memory"); } -static __inline__ void _raw_write_unlock(rwlock_t *rw) +static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) { __asm__ __volatile__("eieio # write_unlock": : :"memory"); rw->lock = 0; } -#else - -extern void _raw_read_lock(rwlock_t *rw); -extern void _raw_read_unlock(rwlock_t *rw); -extern void _raw_write_lock(rwlock_t *rw); -extern void _raw_write_unlock(rwlock_t *rw); -extern int _raw_read_trylock(rwlock_t *rw); -extern int _raw_write_trylock(rwlock_t *rw); - -#endif - #endif /* __ASM_SPINLOCK_H */ -#endif /* __KERNEL__ */ diff --git a/include/asm-ppc/spinlock_types.h b/include/asm-ppc/spinlock_types.h new file mode 100644 index 0000000000000..7919ccc75b8a0 --- /dev/null +++ b/include/asm-ppc/spinlock_types.h @@ -0,0 +1,20 @@ +#ifndef __ASM_SPINLOCK_TYPES_H +#define __ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned long lock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile signed int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { 0 } + +#endif diff --git a/include/asm-ppc64/spinlock.h b/include/asm-ppc64/spinlock.h index acd11564dd752..14cb895bb6072 100644 --- a/include/asm-ppc64/spinlock.h +++ b/include/asm-ppc64/spinlock.h @@ -15,36 +15,42 @@ * 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. + * + * (the type definitions are in asm/spinlock_types.h) */ #include <linux/config.h> #include <asm/paca.h> #include <asm/hvcall.h> #include <asm/iSeries/HvCall.h> -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; +#define __raw_spin_is_locked(x) ((x)->slock != 0) -typedef struct { - volatile signed int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; +/* + * This returns the old value in the lock, so we succeeded + * in getting the lock if the return value is 0. + */ +static __inline__ unsigned long __spin_trylock(raw_spinlock_t *lock) +{ + unsigned long tmp, tmp2; -#ifdef __KERNEL__ -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } + __asm__ __volatile__( +" lwz %1,%3(13) # __spin_trylock\n\ +1: lwarx %0,0,%2\n\ + cmpwi 0,%0,0\n\ + bne- 2f\n\ + stwcx. %1,0,%2\n\ + bne- 1b\n\ + isync\n\ +2:" : "=&r" (tmp), "=&r" (tmp2) + : "r" (&lock->slock), "i" (offsetof(struct paca_struct, lock_token)) + : "cr0", "memory"); -#define spin_is_locked(x) ((x)->lock != 0) -#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) + return tmp; +} -static __inline__ void _raw_spin_unlock(spinlock_t *lock) +static int __inline__ __raw_spin_trylock(raw_spinlock_t *lock) { - __asm__ __volatile__("lwsync # spin_unlock": : :"memory"); - lock->lock = 0; + return __spin_trylock(lock) == 0; } /* @@ -64,44 +70,15 @@ static __inline__ void _raw_spin_unlock(spinlock_t *lock) #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) /* We only yield to the hypervisor if we are in shared processor mode */ #define SHARED_PROCESSOR (get_paca()->lppaca.shared_proc) -extern void __spin_yield(spinlock_t *lock); -extern void __rw_yield(rwlock_t *lock); +extern void __spin_yield(raw_spinlock_t *lock); +extern void __rw_yield(raw_rwlock_t *lock); #else /* SPLPAR || ISERIES */ #define __spin_yield(x) barrier() #define __rw_yield(x) barrier() #define SHARED_PROCESSOR 0 #endif -extern void spin_unlock_wait(spinlock_t *lock); - -/* - * This returns the old value in the lock, so we succeeded - * in getting the lock if the return value is 0. - */ -static __inline__ unsigned long __spin_trylock(spinlock_t *lock) -{ - unsigned long tmp, tmp2; - - __asm__ __volatile__( -" lwz %1,%3(13) # __spin_trylock\n\ -1: lwarx %0,0,%2\n\ - cmpwi 0,%0,0\n\ - bne- 2f\n\ - stwcx. %1,0,%2\n\ - bne- 1b\n\ - isync\n\ -2:" : "=&r" (tmp), "=&r" (tmp2) - : "r" (&lock->lock), "i" (offsetof(struct paca_struct, lock_token)) - : "cr0", "memory"); - - return tmp; -} - -static int __inline__ _raw_spin_trylock(spinlock_t *lock) -{ - return __spin_trylock(lock) == 0; -} -static void __inline__ _raw_spin_lock(spinlock_t *lock) +static void __inline__ __raw_spin_lock(raw_spinlock_t *lock) { while (1) { if (likely(__spin_trylock(lock) == 0)) @@ -110,12 +87,12 @@ static void __inline__ _raw_spin_lock(spinlock_t *lock) HMT_low(); if (SHARED_PROCESSOR) __spin_yield(lock); - } while (unlikely(lock->lock != 0)); + } while (unlikely(lock->slock != 0)); HMT_medium(); } } -static void __inline__ _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags) +static void __inline__ __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) { unsigned long flags_dis; @@ -128,12 +105,20 @@ static void __inline__ _raw_spin_lock_flags(spinlock_t *lock, unsigned long flag HMT_low(); if (SHARED_PROCESSOR) __spin_yield(lock); - } while (unlikely(lock->lock != 0)); + } while (unlikely(lock->slock != 0)); HMT_medium(); local_irq_restore(flags_dis); } } +static __inline__ void __raw_spin_unlock(raw_spinlock_t *lock) +{ + __asm__ __volatile__("lwsync # __raw_spin_unlock": : :"memory"); + lock->slock = 0; +} + +extern void __raw_spin_unlock_wait(raw_spinlock_t *lock); + /* * Read-write spinlocks, allowing multiple readers * but only one writer. @@ -144,24 +129,15 @@ static void __inline__ _raw_spin_lock_flags(spinlock_t *lock, unsigned long flag * irq-safe write-lock, but readers can get non-irqsafe * read-locks. */ -#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } -#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) - -#define read_can_lock(rw) ((rw)->lock >= 0) -#define write_can_lock(rw) (!(rw)->lock) - -static __inline__ void _raw_write_unlock(rwlock_t *rw) -{ - __asm__ __volatile__("lwsync # write_unlock": : :"memory"); - rw->lock = 0; -} +#define __raw_read_can_lock(rw) ((rw)->lock >= 0) +#define __raw_write_can_lock(rw) (!(rw)->lock) /* * This returns the old value in the lock + 1, * so we got a read lock if the return value is > 0. */ -static long __inline__ __read_trylock(rwlock_t *rw) +static long __inline__ __read_trylock(raw_rwlock_t *rw) { long tmp; @@ -180,45 +156,11 @@ static long __inline__ __read_trylock(rwlock_t *rw) return tmp; } -static int __inline__ _raw_read_trylock(rwlock_t *rw) -{ - return __read_trylock(rw) > 0; -} - -static void __inline__ _raw_read_lock(rwlock_t *rw) -{ - while (1) { - if (likely(__read_trylock(rw) > 0)) - break; - do { - HMT_low(); - if (SHARED_PROCESSOR) - __rw_yield(rw); - } while (unlikely(rw->lock < 0)); - HMT_medium(); - } -} - -static void __inline__ _raw_read_unlock(rwlock_t *rw) -{ - long tmp; - - __asm__ __volatile__( - "eieio # read_unlock\n\ -1: lwarx %0,0,%1\n\ - addic %0,%0,-1\n\ - stwcx. %0,0,%1\n\ - bne- 1b" - : "=&r"(tmp) - : "r"(&rw->lock) - : "cr0", "memory"); -} - /* * This returns the old value in the lock, * so we got the write lock if the return value is 0. */ -static __inline__ long __write_trylock(rwlock_t *rw) +static __inline__ long __write_trylock(raw_rwlock_t *rw) { long tmp, tmp2; @@ -237,12 +179,21 @@ static __inline__ long __write_trylock(rwlock_t *rw) return tmp; } -static int __inline__ _raw_write_trylock(rwlock_t *rw) +static void __inline__ __raw_read_lock(raw_rwlock_t *rw) { - return __write_trylock(rw) == 0; + while (1) { + if (likely(__read_trylock(rw) > 0)) + break; + do { + HMT_low(); + if (SHARED_PROCESSOR) + __rw_yield(rw); + } while (unlikely(rw->lock < 0)); + HMT_medium(); + } } -static void __inline__ _raw_write_lock(rwlock_t *rw) +static void __inline__ __raw_write_lock(raw_rwlock_t *rw) { while (1) { if (likely(__write_trylock(rw) == 0)) @@ -256,5 +207,35 @@ static void __inline__ _raw_write_lock(rwlock_t *rw) } } -#endif /* __KERNEL__ */ +static int __inline__ __raw_read_trylock(raw_rwlock_t *rw) +{ + return __read_trylock(rw) > 0; +} + +static int __inline__ __raw_write_trylock(raw_rwlock_t *rw) +{ + return __write_trylock(rw) == 0; +} + +static void __inline__ __raw_read_unlock(raw_rwlock_t *rw) +{ + long tmp; + + __asm__ __volatile__( + "eieio # read_unlock\n\ +1: lwarx %0,0,%1\n\ + addic %0,%0,-1\n\ + stwcx. %0,0,%1\n\ + bne- 1b" + : "=&r"(tmp) + : "r"(&rw->lock) + : "cr0", "memory"); +} + +static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) +{ + __asm__ __volatile__("lwsync # write_unlock": : :"memory"); + rw->lock = 0; +} + #endif /* __ASM_SPINLOCK_H */ diff --git a/include/asm-ppc64/spinlock_types.h b/include/asm-ppc64/spinlock_types.h new file mode 100644 index 0000000000000..a37c8eabb9f29 --- /dev/null +++ b/include/asm-ppc64/spinlock_types.h @@ -0,0 +1,20 @@ +#ifndef __ASM_SPINLOCK_TYPES_H +#define __ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned int slock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile signed int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { 0 } + +#endif diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h index 321b23bba1ecf..273dbecf8acef 100644 --- a/include/asm-s390/spinlock.h +++ b/include/asm-s390/spinlock.h @@ -27,25 +27,19 @@ _raw_compare_and_swap(volatile unsigned int *lock, * on the local processor, one does not. * * We make no fairness assumptions. They have a cost. + * + * (the type definitions are in asm/spinlock_types.h) */ -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} __attribute__ ((aligned (4))) spinlock_t; - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } -#define spin_lock_init(lp) do { (lp)->lock = 0; } while(0) -#define spin_unlock_wait(lp) do { barrier(); } while(((volatile spinlock_t *)(lp))->lock) -#define spin_is_locked(x) ((x)->lock != 0) -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) +#define __raw_spin_is_locked(x) ((x)->lock != 0) +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) +#define __raw_spin_unlock_wait(lock) \ + do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0) -extern void _raw_spin_lock_wait(spinlock_t *lp, unsigned int pc); -extern int _raw_spin_trylock_retry(spinlock_t *lp, unsigned int pc); +extern void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc); +extern int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc); -static inline void _raw_spin_lock(spinlock_t *lp) +static inline void __raw_spin_lock(raw_spinlock_t *lp) { unsigned long pc = 1 | (unsigned long) __builtin_return_address(0); @@ -53,7 +47,7 @@ static inline void _raw_spin_lock(spinlock_t *lp) _raw_spin_lock_wait(lp, pc); } -static inline int _raw_spin_trylock(spinlock_t *lp) +static inline int __raw_spin_trylock(raw_spinlock_t *lp) { unsigned long pc = 1 | (unsigned long) __builtin_return_address(0); @@ -62,7 +56,7 @@ static inline int _raw_spin_trylock(spinlock_t *lp) return _raw_spin_trylock_retry(lp, pc); } -static inline void _raw_spin_unlock(spinlock_t *lp) +static inline void __raw_spin_unlock(raw_spinlock_t *lp) { _raw_compare_and_swap(&lp->lock, lp->lock, 0); } @@ -77,36 +71,25 @@ static inline void _raw_spin_unlock(spinlock_t *lp) * irq-safe write-lock, but readers can get non-irqsafe * read-locks. */ -typedef struct { - volatile unsigned int lock; - volatile unsigned long owner_pc; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; - -#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } - -#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) /** * read_can_lock - would read_trylock() succeed? * @lock: the rwlock in question. */ -#define read_can_lock(x) ((int)(x)->lock >= 0) +#define __raw_read_can_lock(x) ((int)(x)->lock >= 0) /** * write_can_lock - would write_trylock() succeed? * @lock: the rwlock in question. */ -#define write_can_lock(x) ((x)->lock == 0) +#define __raw_write_can_lock(x) ((x)->lock == 0) -extern void _raw_read_lock_wait(rwlock_t *lp); -extern int _raw_read_trylock_retry(rwlock_t *lp); -extern void _raw_write_lock_wait(rwlock_t *lp); -extern int _raw_write_trylock_retry(rwlock_t *lp); +extern void _raw_read_lock_wait(raw_rwlock_t *lp); +extern int _raw_read_trylock_retry(raw_rwlock_t *lp); +extern void _raw_write_lock_wait(raw_rwlock_t *lp); +extern int _raw_write_trylock_retry(raw_rwlock_t *lp); -static inline void _raw_read_lock(rwlock_t *rw) +static inline void __raw_read_lock(raw_rwlock_t *rw) { unsigned int old; old = rw->lock & 0x7fffffffU; @@ -114,7 +97,7 @@ static inline void _raw_read_lock(rwlock_t *rw) _raw_read_lock_wait(rw); } -static inline void _raw_read_unlock(rwlock_t *rw) +static inline void __raw_read_unlock(raw_rwlock_t *rw) { unsigned int old, cmp; @@ -125,18 +108,18 @@ static inline void _raw_read_unlock(rwlock_t *rw) } while (cmp != old); } -static inline void _raw_write_lock(rwlock_t *rw) +static inline void __raw_write_lock(raw_rwlock_t *rw) { if (unlikely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000) != 0)) _raw_write_lock_wait(rw); } -static inline void _raw_write_unlock(rwlock_t *rw) +static inline void __raw_write_unlock(raw_rwlock_t *rw) { _raw_compare_and_swap(&rw->lock, 0x80000000, 0); } -static inline int _raw_read_trylock(rwlock_t *rw) +static inline int __raw_read_trylock(raw_rwlock_t *rw) { unsigned int old; old = rw->lock & 0x7fffffffU; @@ -145,7 +128,7 @@ static inline int _raw_read_trylock(rwlock_t *rw) return _raw_read_trylock_retry(rw); } -static inline int _raw_write_trylock(rwlock_t *rw) +static inline int __raw_write_trylock(raw_rwlock_t *rw) { if (likely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)) return 1; diff --git a/include/asm-s390/spinlock_types.h b/include/asm-s390/spinlock_types.h new file mode 100644 index 0000000000000..f79a2216204f5 --- /dev/null +++ b/include/asm-s390/spinlock_types.h @@ -0,0 +1,21 @@ +#ifndef __ASM_SPINLOCK_TYPES_H +#define __ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned int lock; +} __attribute__ ((aligned (4))) raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile unsigned int lock; + volatile unsigned int owner_pc; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { 0, 0 } + +#endif diff --git a/include/asm-sh/spinlock.h b/include/asm-sh/spinlock.h index e770b55649ebb..846322d4c35d4 100644 --- a/include/asm-sh/spinlock.h +++ b/include/asm-sh/spinlock.h @@ -15,20 +15,11 @@ /* * Your basic SMP spinlocks, allowing only a single CPU anywhere */ -typedef struct { - volatile unsigned long lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } - -#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) - -#define spin_is_locked(x) ((x)->lock != 0) -#define spin_unlock_wait(x) do { barrier(); } while (spin_is_locked(x)) -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) +#define __raw_spin_is_locked(x) ((x)->lock != 0) +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) +#define __raw_spin_unlock_wait(x) \ + do { cpu_relax(); } while (__raw_spin_is_locked(x)) /* * Simple spin lock operations. There are two variants, one clears IRQ's @@ -36,7 +27,7 @@ typedef struct { * * We make no fairness assumptions. They have a cost. */ -static inline void _raw_spin_lock(spinlock_t *lock) +static inline void __raw_spin_lock(raw_spinlock_t *lock) { __asm__ __volatile__ ( "1:\n\t" @@ -49,14 +40,14 @@ static inline void _raw_spin_lock(spinlock_t *lock) ); } -static inline void _raw_spin_unlock(spinlock_t *lock) +static inline void __raw_spin_unlock(raw_spinlock_t *lock) { assert_spin_locked(lock); lock->lock = 0; } -#define _raw_spin_trylock(x) (!test_and_set_bit(0, &(x)->lock)) +#define __raw_spin_trylock(x) (!test_and_set_bit(0, &(x)->lock)) /* * Read-write spinlocks, allowing multiple readers but only one writer. @@ -66,51 +57,40 @@ static inline void _raw_spin_unlock(spinlock_t *lock) * needs to get a irq-safe write-lock, but readers can get non-irqsafe * read-locks. */ -typedef struct { - spinlock_t lock; - atomic_t counter; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; - -#define RW_LOCK_BIAS 0x01000000 -#define RW_LOCK_UNLOCKED (rwlock_t) { { 0 }, { RW_LOCK_BIAS } } -#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while (0) - -static inline void _raw_read_lock(rwlock_t *rw) + +static inline void __raw_read_lock(raw_rwlock_t *rw) { - _raw_spin_lock(&rw->lock); + __raw_spin_lock(&rw->lock); atomic_inc(&rw->counter); - _raw_spin_unlock(&rw->lock); + __raw_spin_unlock(&rw->lock); } -static inline void _raw_read_unlock(rwlock_t *rw) +static inline void __raw_read_unlock(raw_rwlock_t *rw) { - _raw_spin_lock(&rw->lock); + __raw_spin_lock(&rw->lock); atomic_dec(&rw->counter); - _raw_spin_unlock(&rw->lock); + __raw_spin_unlock(&rw->lock); } -static inline void _raw_write_lock(rwlock_t *rw) +static inline void __raw_write_lock(raw_rwlock_t *rw) { - _raw_spin_lock(&rw->lock); + __raw_spin_lock(&rw->lock); atomic_set(&rw->counter, -1); } -static inline void _raw_write_unlock(rwlock_t *rw) +static inline void __raw_write_unlock(raw_rwlock_t *rw) { atomic_set(&rw->counter, 0); - _raw_spin_unlock(&rw->lock); + __raw_spin_unlock(&rw->lock); } -#define _raw_read_trylock(lock) generic_raw_read_trylock(lock) +#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) -static inline int _raw_write_trylock(rwlock_t *rw) +static inline int __raw_write_trylock(raw_rwlock_t *rw) { if (atomic_sub_and_test(RW_LOCK_BIAS, &rw->counter)) return 1; @@ -121,4 +101,3 @@ static inline int _raw_write_trylock(rwlock_t *rw) } #endif /* __ASM_SH_SPINLOCK_H */ - diff --git a/include/asm-sh/spinlock_types.h b/include/asm-sh/spinlock_types.h new file mode 100644 index 0000000000000..8c41b6c3aac87 --- /dev/null +++ b/include/asm-sh/spinlock_types.h @@ -0,0 +1,22 @@ +#ifndef __ASM_SH_SPINLOCK_TYPES_H +#define __ASM_SH_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned long lock; +} raw_spinlock_t; + +#define __SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + raw_spinlock_t lock; + atomic_t counter; +} raw_rwlock_t; + +#define RW_LOCK_BIAS 0x01000000 +#define __RAW_RW_LOCK_UNLOCKED { { 0 }, { RW_LOCK_BIAS } } + +#endif diff --git a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h index 0cbd87ad49128..111727a2bb4e4 100644 --- a/include/asm-sparc/spinlock.h +++ b/include/asm-sparc/spinlock.h @@ -12,96 +12,12 @@ #include <asm/psr.h> -#ifdef CONFIG_DEBUG_SPINLOCK -struct _spinlock_debug { - unsigned char lock; - unsigned long owner_pc; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -}; -typedef struct _spinlock_debug spinlock_t; - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0 } -#define spin_lock_init(lp) do { *(lp)= SPIN_LOCK_UNLOCKED; } while(0) -#define spin_is_locked(lp) (*((volatile unsigned char *)(&((lp)->lock))) != 0) -#define spin_unlock_wait(lp) do { barrier(); } while(*(volatile unsigned char *)(&(lp)->lock)) - -extern void _do_spin_lock(spinlock_t *lock, char *str); -extern int _spin_trylock(spinlock_t *lock); -extern void _do_spin_unlock(spinlock_t *lock); - -#define _raw_spin_trylock(lp) _spin_trylock(lp) -#define _raw_spin_lock(lock) _do_spin_lock(lock, "spin_lock") -#define _raw_spin_unlock(lock) _do_spin_unlock(lock) - -struct _rwlock_debug { - volatile unsigned int lock; - unsigned long owner_pc; - unsigned long reader_pc[NR_CPUS]; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -}; -typedef struct _rwlock_debug rwlock_t; - -#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, {0} } - -#define rwlock_init(lp) do { *(lp)= RW_LOCK_UNLOCKED; } while(0) - -extern void _do_read_lock(rwlock_t *rw, char *str); -extern void _do_read_unlock(rwlock_t *rw, char *str); -extern void _do_write_lock(rwlock_t *rw, char *str); -extern void _do_write_unlock(rwlock_t *rw); - -#define _raw_read_lock(lock) \ -do { unsigned long flags; \ - local_irq_save(flags); \ - _do_read_lock(lock, "read_lock"); \ - local_irq_restore(flags); \ -} while(0) - -#define _raw_read_unlock(lock) \ -do { unsigned long flags; \ - local_irq_save(flags); \ - _do_read_unlock(lock, "read_unlock"); \ - local_irq_restore(flags); \ -} while(0) - -#define _raw_write_lock(lock) \ -do { unsigned long flags; \ - local_irq_save(flags); \ - _do_write_lock(lock, "write_lock"); \ - local_irq_restore(flags); \ -} while(0) - -#define _raw_write_unlock(lock) \ -do { unsigned long flags; \ - local_irq_save(flags); \ - _do_write_unlock(lock); \ - local_irq_restore(flags); \ -} while(0) - -#else /* !CONFIG_DEBUG_SPINLOCK */ - -typedef struct { - unsigned char lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } - -#define spin_lock_init(lock) (*((unsigned char *)(lock)) = 0) -#define spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0) +#define __raw_spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0) -#define spin_unlock_wait(lock) \ -do { \ - barrier(); \ -} while(*((volatile unsigned char *)lock)) +#define __raw_spin_unlock_wait(lock) \ + do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0) -extern __inline__ void _raw_spin_lock(spinlock_t *lock) +extern __inline__ void __raw_spin_lock(raw_spinlock_t *lock) { __asm__ __volatile__( "\n1:\n\t" @@ -121,7 +37,7 @@ extern __inline__ void _raw_spin_lock(spinlock_t *lock) : "g2", "memory", "cc"); } -extern __inline__ int _raw_spin_trylock(spinlock_t *lock) +extern __inline__ int __raw_spin_trylock(raw_spinlock_t *lock) { unsigned int result; __asm__ __volatile__("ldstub [%1], %0" @@ -131,7 +47,7 @@ extern __inline__ int _raw_spin_trylock(spinlock_t *lock) return (result == 0); } -extern __inline__ void _raw_spin_unlock(spinlock_t *lock) +extern __inline__ void __raw_spin_unlock(raw_spinlock_t *lock) { __asm__ __volatile__("stb %%g0, [%0]" : : "r" (lock) : "memory"); } @@ -147,23 +63,11 @@ extern __inline__ void _raw_spin_unlock(spinlock_t *lock) * * XXX This might create some problems with my dual spinlock * XXX scheme, deadlocks etc. -DaveM - */ -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; - -#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } - -#define rwlock_init(lp) do { *(lp)= RW_LOCK_UNLOCKED; } while(0) - - -/* Sort of like atomic_t's on Sparc, but even more clever. + * + * Sort of like atomic_t's on Sparc, but even more clever. * * ------------------------------------ - * | 24-bit counter | wlock | rwlock_t + * | 24-bit counter | wlock | raw_rwlock_t * ------------------------------------ * 31 8 7 0 * @@ -174,9 +78,9 @@ typedef struct { * * Unfortunately this scheme limits us to ~16,000,000 cpus. */ -extern __inline__ void _read_lock(rwlock_t *rw) +extern __inline__ void __read_lock(raw_rwlock_t *rw) { - register rwlock_t *lp asm("g1"); + register raw_rwlock_t *lp asm("g1"); lp = rw; __asm__ __volatile__( "mov %%o7, %%g4\n\t" @@ -187,16 +91,16 @@ extern __inline__ void _read_lock(rwlock_t *rw) : "g2", "g4", "memory", "cc"); } -#define _raw_read_lock(lock) \ +#define __raw_read_lock(lock) \ do { unsigned long flags; \ local_irq_save(flags); \ - _read_lock(lock); \ + __raw_read_lock(lock); \ local_irq_restore(flags); \ } while(0) -extern __inline__ void _read_unlock(rwlock_t *rw) +extern __inline__ void __read_unlock(raw_rwlock_t *rw) { - register rwlock_t *lp asm("g1"); + register raw_rwlock_t *lp asm("g1"); lp = rw; __asm__ __volatile__( "mov %%o7, %%g4\n\t" @@ -207,16 +111,16 @@ extern __inline__ void _read_unlock(rwlock_t *rw) : "g2", "g4", "memory", "cc"); } -#define _raw_read_unlock(lock) \ +#define __raw_read_unlock(lock) \ do { unsigned long flags; \ local_irq_save(flags); \ - _read_unlock(lock); \ + __raw_read_unlock(lock); \ local_irq_restore(flags); \ } while(0) -extern __inline__ void _raw_write_lock(rwlock_t *rw) +extern __inline__ void __raw_write_lock(raw_rwlock_t *rw) { - register rwlock_t *lp asm("g1"); + register raw_rwlock_t *lp asm("g1"); lp = rw; __asm__ __volatile__( "mov %%o7, %%g4\n\t" @@ -227,11 +131,9 @@ extern __inline__ void _raw_write_lock(rwlock_t *rw) : "g2", "g4", "memory", "cc"); } -#define _raw_write_unlock(rw) do { (rw)->lock = 0; } while(0) - -#endif /* CONFIG_DEBUG_SPINLOCK */ +#define __raw_write_unlock(rw) do { (rw)->lock = 0; } while(0) -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) #endif /* !(__ASSEMBLY__) */ diff --git a/include/asm-sparc/spinlock_types.h b/include/asm-sparc/spinlock_types.h new file mode 100644 index 0000000000000..0a0fb116c4ec3 --- /dev/null +++ b/include/asm-sparc/spinlock_types.h @@ -0,0 +1,20 @@ +#ifndef __SPARC_SPINLOCK_TYPES_H +#define __SPARC_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + unsigned char lock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile unsigned int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { 0 } + +#endif diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h index a02c4370eb42e..ec85d12d73b98 100644 --- a/include/asm-sparc64/spinlock.h +++ b/include/asm-sparc64/spinlock.h @@ -29,24 +29,13 @@ * must be pre-V9 branches. */ -#ifndef CONFIG_DEBUG_SPINLOCK +#define __raw_spin_is_locked(lp) ((lp)->lock != 0) -typedef struct { - volatile unsigned char lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) {0,} +#define __raw_spin_unlock_wait(lp) \ + do { rmb(); \ + } while((lp)->lock) -#define spin_lock_init(lp) do { *(lp)= SPIN_LOCK_UNLOCKED; } while(0) -#define spin_is_locked(lp) ((lp)->lock != 0) - -#define spin_unlock_wait(lp) \ -do { rmb(); \ -} while((lp)->lock) - -static inline void _raw_spin_lock(spinlock_t *lock) +static inline void __raw_spin_lock(raw_spinlock_t *lock) { unsigned long tmp; @@ -67,7 +56,7 @@ static inline void _raw_spin_lock(spinlock_t *lock) : "memory"); } -static inline int _raw_spin_trylock(spinlock_t *lock) +static inline int __raw_spin_trylock(raw_spinlock_t *lock) { unsigned long result; @@ -81,7 +70,7 @@ static inline int _raw_spin_trylock(spinlock_t *lock) return (result == 0UL); } -static inline void _raw_spin_unlock(spinlock_t *lock) +static inline void __raw_spin_unlock(raw_spinlock_t *lock) { __asm__ __volatile__( " membar #StoreStore | #LoadStore\n" @@ -91,7 +80,7 @@ static inline void _raw_spin_unlock(spinlock_t *lock) : "memory"); } -static inline void _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags) +static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) { unsigned long tmp1, tmp2; @@ -115,51 +104,9 @@ static inline void _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags) : "memory"); } -#else /* !(CONFIG_DEBUG_SPINLOCK) */ - -typedef struct { - volatile unsigned char lock; - unsigned int owner_pc, owner_cpu; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0, 0xff } -#define spin_lock_init(lp) do { *(lp)= SPIN_LOCK_UNLOCKED; } while(0) -#define spin_is_locked(__lock) ((__lock)->lock != 0) -#define spin_unlock_wait(__lock) \ -do { \ - rmb(); \ -} while((__lock)->lock) - -extern void _do_spin_lock(spinlock_t *lock, char *str, unsigned long caller); -extern void _do_spin_unlock(spinlock_t *lock); -extern int _do_spin_trylock(spinlock_t *lock, unsigned long caller); - -#define _raw_spin_trylock(lp) \ - _do_spin_trylock(lp, (unsigned long) __builtin_return_address(0)) -#define _raw_spin_lock(lock) \ - _do_spin_lock(lock, "spin_lock", \ - (unsigned long) __builtin_return_address(0)) -#define _raw_spin_unlock(lock) _do_spin_unlock(lock) -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) - -#endif /* CONFIG_DEBUG_SPINLOCK */ - /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ -#ifndef CONFIG_DEBUG_SPINLOCK - -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) {0,} -#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) - -static void inline __read_lock(rwlock_t *lock) +static void inline __read_lock(raw_rwlock_t *lock) { unsigned long tmp1, tmp2; @@ -184,7 +131,7 @@ static void inline __read_lock(rwlock_t *lock) : "memory"); } -static void inline __read_unlock(rwlock_t *lock) +static void inline __read_unlock(raw_rwlock_t *lock) { unsigned long tmp1, tmp2; @@ -201,7 +148,7 @@ static void inline __read_unlock(rwlock_t *lock) : "memory"); } -static void inline __write_lock(rwlock_t *lock) +static void inline __write_lock(raw_rwlock_t *lock) { unsigned long mask, tmp1, tmp2; @@ -228,7 +175,7 @@ static void inline __write_lock(rwlock_t *lock) : "memory"); } -static void inline __write_unlock(rwlock_t *lock) +static void inline __write_unlock(raw_rwlock_t *lock) { __asm__ __volatile__( " membar #LoadStore | #StoreStore\n" @@ -238,7 +185,7 @@ static void inline __write_unlock(rwlock_t *lock) : "memory"); } -static int inline __write_trylock(rwlock_t *lock) +static int inline __write_trylock(raw_rwlock_t *lock) { unsigned long mask, tmp1, tmp2, result; @@ -263,78 +210,15 @@ static int inline __write_trylock(rwlock_t *lock) return result; } -#define _raw_read_lock(p) __read_lock(p) -#define _raw_read_unlock(p) __read_unlock(p) -#define _raw_write_lock(p) __write_lock(p) -#define _raw_write_unlock(p) __write_unlock(p) -#define _raw_write_trylock(p) __write_trylock(p) - -#else /* !(CONFIG_DEBUG_SPINLOCK) */ - -typedef struct { - volatile unsigned long lock; - unsigned int writer_pc, writer_cpu; - unsigned int reader_pc[NR_CPUS]; -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0xff, { } } -#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) - -extern void _do_read_lock(rwlock_t *rw, char *str, unsigned long caller); -extern void _do_read_unlock(rwlock_t *rw, char *str, unsigned long caller); -extern void _do_write_lock(rwlock_t *rw, char *str, unsigned long caller); -extern void _do_write_unlock(rwlock_t *rw, unsigned long caller); -extern int _do_write_trylock(rwlock_t *rw, char *str, unsigned long caller); - -#define _raw_read_lock(lock) \ -do { unsigned long flags; \ - local_irq_save(flags); \ - _do_read_lock(lock, "read_lock", \ - (unsigned long) __builtin_return_address(0)); \ - local_irq_restore(flags); \ -} while(0) - -#define _raw_read_unlock(lock) \ -do { unsigned long flags; \ - local_irq_save(flags); \ - _do_read_unlock(lock, "read_unlock", \ - (unsigned long) __builtin_return_address(0)); \ - local_irq_restore(flags); \ -} while(0) - -#define _raw_write_lock(lock) \ -do { unsigned long flags; \ - local_irq_save(flags); \ - _do_write_lock(lock, "write_lock", \ - (unsigned long) __builtin_return_address(0)); \ - local_irq_restore(flags); \ -} while(0) - -#define _raw_write_unlock(lock) \ -do { unsigned long flags; \ - local_irq_save(flags); \ - _do_write_unlock(lock, \ - (unsigned long) __builtin_return_address(0)); \ - local_irq_restore(flags); \ -} while(0) - -#define _raw_write_trylock(lock) \ -({ unsigned long flags; \ - int val; \ - local_irq_save(flags); \ - val = _do_write_trylock(lock, "write_trylock", \ - (unsigned long) __builtin_return_address(0)); \ - local_irq_restore(flags); \ - val; \ -}) - -#endif /* CONFIG_DEBUG_SPINLOCK */ - -#define _raw_read_trylock(lock) generic_raw_read_trylock(lock) -#define read_can_lock(rw) (!((rw)->lock & 0x80000000UL)) -#define write_can_lock(rw) (!(rw)->lock) +#define __raw_read_lock(p) __read_lock(p) +#define __raw_read_unlock(p) __read_unlock(p) +#define __raw_write_lock(p) __write_lock(p) +#define __raw_write_unlock(p) __write_unlock(p) +#define __raw_write_trylock(p) __write_trylock(p) + +#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) +#define __raw_read_can_lock(rw) (!((rw)->lock & 0x80000000UL)) +#define __raw_write_can_lock(rw) (!(rw)->lock) #endif /* !(__ASSEMBLY__) */ diff --git a/include/asm-sparc64/spinlock_types.h b/include/asm-sparc64/spinlock_types.h new file mode 100644 index 0000000000000..e128112a0d7c8 --- /dev/null +++ b/include/asm-sparc64/spinlock_types.h @@ -0,0 +1,20 @@ +#ifndef __SPARC64_SPINLOCK_TYPES_H +#define __SPARC64_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned char lock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile unsigned int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { 0 } + +#endif diff --git a/include/asm-x86_64/spinlock.h b/include/asm-x86_64/spinlock.h index 5aeb57a3baad3..69636831ad2f4 100644 --- a/include/asm-x86_64/spinlock.h +++ b/include/asm-x86_64/spinlock.h @@ -6,47 +6,21 @@ #include <asm/page.h> #include <linux/config.h> -extern int printk(const char * fmt, ...) - __attribute__ ((format (printf, 1, 2))); - /* * Your basic SMP spinlocks, allowing only a single CPU anywhere - */ - -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_DEBUG_SPINLOCK - unsigned magic; -#endif -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} spinlock_t; - -#define SPINLOCK_MAGIC 0xdead4ead - -#ifdef CONFIG_DEBUG_SPINLOCK -#define SPINLOCK_MAGIC_INIT , SPINLOCK_MAGIC -#else -#define SPINLOCK_MAGIC_INIT /* */ -#endif - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT } - -#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0) - -/* + * * Simple spin lock operations. There are two variants, one clears IRQ's * on the local processor, one does not. * * We make no fairness assumptions. They have a cost. + * + * (the type definitions are in asm/spinlock_types.h) */ -#define spin_is_locked(x) (*(volatile signed char *)(&(x)->lock) <= 0) -#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) -#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) +#define __raw_spin_is_locked(x) \ + (*(volatile signed char *)(&(x)->slock) <= 0) -#define spin_lock_string \ +#define __raw_spin_lock_string \ "\n1:\t" \ "lock ; decb %0\n\t" \ "js 2f\n" \ @@ -58,74 +32,40 @@ typedef struct { "jmp 1b\n" \ LOCK_SECTION_END -/* - * This works. Despite all the confusion. - * (except on PPro SMP or if we are using OOSTORE) - * (PPro errata 66, 92) - */ - -#if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE) - -#define spin_unlock_string \ +#define __raw_spin_unlock_string \ "movb $1,%0" \ - :"=m" (lock->lock) : : "memory" - - -static inline void _raw_spin_unlock(spinlock_t *lock) -{ -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(lock->magic != SPINLOCK_MAGIC); - assert_spin_locked(lock); -#endif - __asm__ __volatile__( - spin_unlock_string - ); -} - -#else - -#define spin_unlock_string \ - "xchgb %b0, %1" \ - :"=q" (oldval), "=m" (lock->lock) \ - :"0" (oldval) : "memory" + :"=m" (lock->slock) : : "memory" -static inline void _raw_spin_unlock(spinlock_t *lock) +static inline void __raw_spin_lock(raw_spinlock_t *lock) { - char oldval = 1; -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(lock->magic != SPINLOCK_MAGIC); - assert_spin_locked(lock); -#endif __asm__ __volatile__( - spin_unlock_string - ); + __raw_spin_lock_string + :"=m" (lock->slock) : : "memory"); } -#endif +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) -static inline int _raw_spin_trylock(spinlock_t *lock) +static inline int __raw_spin_trylock(raw_spinlock_t *lock) { char oldval; + __asm__ __volatile__( "xchgb %b0,%1" - :"=q" (oldval), "=m" (lock->lock) + :"=q" (oldval), "=m" (lock->slock) :"0" (0) : "memory"); + return oldval > 0; } -static inline void _raw_spin_lock(spinlock_t *lock) +static inline void __raw_spin_unlock(raw_spinlock_t *lock) { -#ifdef CONFIG_DEBUG_SPINLOCK - if (lock->magic != SPINLOCK_MAGIC) { - printk("eip: %p\n", __builtin_return_address(0)); - BUG(); - } -#endif __asm__ __volatile__( - spin_lock_string - :"=m" (lock->lock) : : "memory"); + __raw_spin_unlock_string + ); } +#define __raw_spin_unlock_wait(lock) \ + do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0) /* * Read-write spinlocks, allowing multiple readers @@ -136,33 +76,7 @@ static inline void _raw_spin_lock(spinlock_t *lock) * can "mix" irq-safe locks - any writer needs to get a * irq-safe write-lock, but readers can get non-irqsafe * read-locks. - */ -typedef struct { - volatile unsigned int lock; -#ifdef CONFIG_DEBUG_SPINLOCK - unsigned magic; -#endif -#ifdef CONFIG_PREEMPT - unsigned int break_lock; -#endif -} rwlock_t; - -#define RWLOCK_MAGIC 0xdeaf1eed - -#ifdef CONFIG_DEBUG_SPINLOCK -#define RWLOCK_MAGIC_INIT , RWLOCK_MAGIC -#else -#define RWLOCK_MAGIC_INIT /* */ -#endif - -#define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT } - -#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) - -#define read_can_lock(x) ((int)(x)->lock > 0) -#define write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) - -/* + * * On x86, we implement read-write locks as a 32-bit counter * with the high bit (sign) being the "contended" bit. * @@ -170,29 +84,24 @@ typedef struct { * * Changed to use the same technique as rw semaphores. See * semaphore.h for details. -ben + * + * the helpers are in arch/i386/kernel/semaphore.c */ -/* the spinlock helpers are in arch/i386/kernel/semaphore.c */ -static inline void _raw_read_lock(rwlock_t *rw) +#define __raw_read_can_lock(x) ((int)(x)->lock > 0) +#define __raw_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) + +static inline void __raw_read_lock(raw_rwlock_t *rw) { -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(rw->magic != RWLOCK_MAGIC); -#endif __build_read_lock(rw, "__read_lock_failed"); } -static inline void _raw_write_lock(rwlock_t *rw) +static inline void __raw_write_lock(raw_rwlock_t *rw) { -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(rw->magic != RWLOCK_MAGIC); -#endif __build_write_lock(rw, "__write_lock_failed"); } -#define _raw_read_unlock(rw) asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory") -#define _raw_write_unlock(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory") - -static inline int _raw_read_trylock(rwlock_t *lock) +static inline int __raw_read_trylock(raw_rwlock_t *lock) { atomic_t *count = (atomic_t *)lock; atomic_dec(count); @@ -202,7 +111,7 @@ static inline int _raw_read_trylock(rwlock_t *lock) return 0; } -static inline int _raw_write_trylock(rwlock_t *lock) +static inline int __raw_write_trylock(raw_rwlock_t *lock) { atomic_t *count = (atomic_t *)lock; if (atomic_sub_and_test(RW_LOCK_BIAS, count)) @@ -211,4 +120,15 @@ static inline int _raw_write_trylock(rwlock_t *lock) return 0; } +static inline void __raw_read_unlock(raw_rwlock_t *rw) +{ + asm volatile("lock ; incl %0" :"=m" (rw->lock) : : "memory"); +} + +static inline void __raw_write_unlock(raw_rwlock_t *rw) +{ + asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0" + : "=m" (rw->lock) : : "memory"); +} + #endif /* __ASM_SPINLOCK_H */ diff --git a/include/asm-x86_64/spinlock_types.h b/include/asm-x86_64/spinlock_types.h new file mode 100644 index 0000000000000..59efe849f351f --- /dev/null +++ b/include/asm-x86_64/spinlock_types.h @@ -0,0 +1,20 @@ +#ifndef __ASM_SPINLOCK_TYPES_H +#define __ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned int slock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 1 } + +typedef struct { + volatile unsigned int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } + +#endif diff --git a/include/linux/bit_spinlock.h b/include/linux/bit_spinlock.h new file mode 100644 index 0000000000000..6b20af0bbb79d --- /dev/null +++ b/include/linux/bit_spinlock.h @@ -0,0 +1,77 @@ +#ifndef __LINUX_BIT_SPINLOCK_H +#define __LINUX_BIT_SPINLOCK_H + +/* + * bit-based spin_lock() + * + * Don't use this unless you really need to: spin_lock() and spin_unlock() + * are significantly faster. + */ +static inline void bit_spin_lock(int bitnum, unsigned long *addr) +{ + /* + * Assuming the lock is uncontended, this never enters + * the body of the outer loop. If it is contended, then + * within the inner loop a non-atomic test is used to + * busywait with less bus contention for a good time to + * attempt to acquire the lock bit. + */ + preempt_disable(); +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + while (test_and_set_bit(bitnum, addr)) { + while (test_bit(bitnum, addr)) { + preempt_enable(); + cpu_relax(); + preempt_disable(); + } + } +#endif + __acquire(bitlock); +} + +/* + * Return true if it was acquired + */ +static inline int bit_spin_trylock(int bitnum, unsigned long *addr) +{ + preempt_disable(); +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + if (test_and_set_bit(bitnum, addr)) { + preempt_enable(); + return 0; + } +#endif + __acquire(bitlock); + return 1; +} + +/* + * bit-based spin_unlock() + */ +static inline void bit_spin_unlock(int bitnum, unsigned long *addr) +{ +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + BUG_ON(!test_bit(bitnum, addr)); + smp_mb__before_clear_bit(); + clear_bit(bitnum, addr); +#endif + preempt_enable(); + __release(bitlock); +} + +/* + * Return true if the lock is held. + */ +static inline int bit_spin_is_locked(int bitnum, unsigned long *addr) +{ +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + return test_bit(bitnum, addr); +#elif defined CONFIG_PREEMPT + return preempt_count(); +#else + return 1; +#endif +} + +#endif /* __LINUX_BIT_SPINLOCK_H */ + diff --git a/include/linux/jbd.h b/include/linux/jbd.h index 84321a4cac93a..de097269bd7f0 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -28,6 +28,7 @@ #include <linux/buffer_head.h> #include <linux/journal-head.h> #include <linux/stddef.h> +#include <linux/bit_spinlock.h> #include <asm/semaphore.h> #endif diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index d6ba068719b61..cdc99a27840d6 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -2,7 +2,48 @@ #define __LINUX_SPINLOCK_H /* - * include/linux/spinlock.h - generic locking declarations + * include/linux/spinlock.h - generic spinlock/rwlock declarations + * + * here's the role of the various spinlock/rwlock related include files: + * + * on SMP builds: + * + * asm/spinlock_types.h: contains the raw_spinlock_t/raw_rwlock_t and the + * initializers + * + * linux/spinlock_types.h: + * defines the generic type and initializers + * + * asm/spinlock.h: contains the __raw_spin_*()/etc. lowlevel + * implementations, mostly inline assembly code + * + * (also included on UP-debug builds:) + * + * linux/spinlock_api_smp.h: + * contains the prototypes for the _spin_*() APIs. + * + * linux/spinlock.h: builds the final spin_*() APIs. + * + * on UP builds: + * + * linux/spinlock_type_up.h: + * contains the generic, simplified UP spinlock type. + * (which is an empty structure on non-debug builds) + * + * linux/spinlock_types.h: + * defines the generic type and initializers + * + * linux/spinlock_up.h: + * contains the __raw_spin_*()/etc. version of UP + * builds. (which are NOPs on non-debug, non-preempt + * builds) + * + * (included on UP-non-debug builds:) + * + * linux/spinlock_api_up.h: + * builds the _spin_*() APIs. + * + * linux/spinlock.h: builds the final spin_*() APIs. */ #include <linux/config.h> @@ -13,7 +54,6 @@ #include <linux/kernel.h> #include <linux/stringify.h> -#include <asm/processor.h> /* for cpu relax */ #include <asm/system.h> /* @@ -35,423 +75,84 @@ #define __lockfunc fastcall __attribute__((section(".spinlock.text"))) /* - * If CONFIG_SMP is set, pull in the _raw_* definitions + * Pull the raw_spinlock_t and raw_rwlock_t definitions: */ -#ifdef CONFIG_SMP - -#define assert_spin_locked(x) BUG_ON(!spin_is_locked(x)) -#include <asm/spinlock.h> - -int __lockfunc _spin_trylock(spinlock_t *lock); -int __lockfunc _read_trylock(rwlock_t *lock); -int __lockfunc _write_trylock(rwlock_t *lock); - -void __lockfunc _spin_lock(spinlock_t *lock) __acquires(spinlock_t); -void __lockfunc _read_lock(rwlock_t *lock) __acquires(rwlock_t); -void __lockfunc _write_lock(rwlock_t *lock) __acquires(rwlock_t); - -void __lockfunc _spin_unlock(spinlock_t *lock) __releases(spinlock_t); -void __lockfunc _read_unlock(rwlock_t *lock) __releases(rwlock_t); -void __lockfunc _write_unlock(rwlock_t *lock) __releases(rwlock_t); - -unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) __acquires(spinlock_t); -unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) __acquires(rwlock_t); -unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) __acquires(rwlock_t); - -void __lockfunc _spin_lock_irq(spinlock_t *lock) __acquires(spinlock_t); -void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(spinlock_t); -void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(rwlock_t); -void __lockfunc _read_lock_bh(rwlock_t *lock) __acquires(rwlock_t); -void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(rwlock_t); -void __lockfunc _write_lock_bh(rwlock_t *lock) __acquires(rwlock_t); - -void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) __releases(spinlock_t); -void __lockfunc _spin_unlock_irq(spinlock_t *lock) __releases(spinlock_t); -void __lockfunc _spin_unlock_bh(spinlock_t *lock) __releases(spinlock_t); -void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) __releases(rwlock_t); -void __lockfunc _read_unlock_irq(rwlock_t *lock) __releases(rwlock_t); -void __lockfunc _read_unlock_bh(rwlock_t *lock) __releases(rwlock_t); -void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) __releases(rwlock_t); -void __lockfunc _write_unlock_irq(rwlock_t *lock) __releases(rwlock_t); -void __lockfunc _write_unlock_bh(rwlock_t *lock) __releases(rwlock_t); - -int __lockfunc _spin_trylock_bh(spinlock_t *lock); -int __lockfunc generic_raw_read_trylock(rwlock_t *lock); -int in_lock_functions(unsigned long addr); - -#else +#include <linux/spinlock_types.h> -#define in_lock_functions(ADDR) 0 +extern int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock); -#if !defined(CONFIG_PREEMPT) && !defined(CONFIG_DEBUG_SPINLOCK) -# define _atomic_dec_and_lock(atomic,lock) atomic_dec_and_test(atomic) -# define ATOMIC_DEC_AND_LOCK -#endif - -#ifdef CONFIG_DEBUG_SPINLOCK - -#define SPINLOCK_MAGIC 0x1D244B3C -typedef struct { - unsigned long magic; - volatile unsigned long lock; - volatile unsigned int babble; - const char *module; - char *owner; - int oline; -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0} - -#define spin_lock_init(x) \ - do { \ - (x)->magic = SPINLOCK_MAGIC; \ - (x)->lock = 0; \ - (x)->babble = 5; \ - (x)->module = __FILE__; \ - (x)->owner = NULL; \ - (x)->oline = 0; \ - } while (0) - -#define CHECK_LOCK(x) \ - do { \ - if ((x)->magic != SPINLOCK_MAGIC) { \ - printk(KERN_ERR "%s:%d: spin_is_locked on uninitialized spinlock %p.\n", \ - __FILE__, __LINE__, (x)); \ - } \ - } while(0) - -#define _raw_spin_lock(x) \ - do { \ - CHECK_LOCK(x); \ - if ((x)->lock&&(x)->babble) { \ - (x)->babble--; \ - printk("%s:%d: spin_lock(%s:%p) already locked by %s/%d\n", \ - __FILE__,__LINE__, (x)->module, \ - (x), (x)->owner, (x)->oline); \ - } \ - (x)->lock = 1; \ - (x)->owner = __FILE__; \ - (x)->oline = __LINE__; \ - } while (0) - -/* without debugging, spin_is_locked on UP always says - * FALSE. --> printk if already locked. */ -#define spin_is_locked(x) \ - ({ \ - CHECK_LOCK(x); \ - if ((x)->lock&&(x)->babble) { \ - (x)->babble--; \ - printk("%s:%d: spin_is_locked(%s:%p) already locked by %s/%d\n", \ - __FILE__,__LINE__, (x)->module, \ - (x), (x)->owner, (x)->oline); \ - } \ - 0; \ - }) - -/* with debugging, assert_spin_locked() on UP does check - * the lock value properly */ -#define assert_spin_locked(x) \ - ({ \ - CHECK_LOCK(x); \ - BUG_ON(!(x)->lock); \ - }) - -/* without debugging, spin_trylock on UP always says - * TRUE. --> printk if already locked. */ -#define _raw_spin_trylock(x) \ - ({ \ - CHECK_LOCK(x); \ - if ((x)->lock&&(x)->babble) { \ - (x)->babble--; \ - printk("%s:%d: spin_trylock(%s:%p) already locked by %s/%d\n", \ - __FILE__,__LINE__, (x)->module, \ - (x), (x)->owner, (x)->oline); \ - } \ - (x)->lock = 1; \ - (x)->owner = __FILE__; \ - (x)->oline = __LINE__; \ - 1; \ - }) - -#define spin_unlock_wait(x) \ - do { \ - CHECK_LOCK(x); \ - if ((x)->lock&&(x)->babble) { \ - (x)->babble--; \ - printk("%s:%d: spin_unlock_wait(%s:%p) owned by %s/%d\n", \ - __FILE__,__LINE__, (x)->module, (x), \ - (x)->owner, (x)->oline); \ - }\ - } while (0) - -#define _raw_spin_unlock(x) \ - do { \ - CHECK_LOCK(x); \ - if (!(x)->lock&&(x)->babble) { \ - (x)->babble--; \ - printk("%s:%d: spin_unlock(%s:%p) not locked\n", \ - __FILE__,__LINE__, (x)->module, (x));\ - } \ - (x)->lock = 0; \ - } while (0) -#else /* - * gcc versions before ~2.95 have a nasty bug with empty initializers. + * Pull the __raw*() functions/declarations (UP-nondebug doesnt need them): */ -#if (__GNUC__ > 2) - typedef struct { } spinlock_t; - #define SPIN_LOCK_UNLOCKED (spinlock_t) { } +#if defined(CONFIG_SMP) +# include <asm/spinlock.h> #else - typedef struct { int gcc_is_buggy; } spinlock_t; - #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } +# include <linux/spinlock_up.h> #endif +#define spin_lock_init(lock) do { *(lock) = SPIN_LOCK_UNLOCKED; } while (0) +#define rwlock_init(lock) do { *(lock) = RW_LOCK_UNLOCKED; } while (0) + +#define spin_is_locked(lock) __raw_spin_is_locked(&(lock)->raw_lock) + +/** + * spin_unlock_wait - wait until the spinlock gets unlocked + * @lock: the spinlock in question. + */ +#define spin_unlock_wait(lock) __raw_spin_unlock_wait(&(lock)->raw_lock) + /* - * If CONFIG_SMP is unset, declare the _raw_* definitions as nops + * Pull the _spin_*()/_read_*()/_write_*() functions/declarations: */ -#define spin_lock_init(lock) do { (void)(lock); } while(0) -#define _raw_spin_lock(lock) do { (void)(lock); } while(0) -#define spin_is_locked(lock) ((void)(lock), 0) -#define assert_spin_locked(lock) do { (void)(lock); } while(0) -#define _raw_spin_trylock(lock) (((void)(lock), 1)) -#define spin_unlock_wait(lock) (void)(lock) -#define _raw_spin_unlock(lock) do { (void)(lock); } while(0) -#endif /* CONFIG_DEBUG_SPINLOCK */ - -/* RW spinlocks: No debug version */ - -#if (__GNUC__ > 2) - typedef struct { } rwlock_t; - #define RW_LOCK_UNLOCKED (rwlock_t) { } +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) +# include <linux/spinlock_api_smp.h> #else - typedef struct { int gcc_is_buggy; } rwlock_t; - #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } +# include <linux/spinlock_api_up.h> #endif -#define rwlock_init(lock) do { (void)(lock); } while(0) -#define _raw_read_lock(lock) do { (void)(lock); } while(0) -#define _raw_read_unlock(lock) do { (void)(lock); } while(0) -#define _raw_write_lock(lock) do { (void)(lock); } while(0) -#define _raw_write_unlock(lock) do { (void)(lock); } while(0) -#define read_can_lock(lock) (((void)(lock), 1)) -#define write_can_lock(lock) (((void)(lock), 1)) -#define _raw_read_trylock(lock) ({ (void)(lock); (1); }) -#define _raw_write_trylock(lock) ({ (void)(lock); (1); }) - -#define _spin_trylock(lock) ({preempt_disable(); _raw_spin_trylock(lock) ? \ - 1 : ({preempt_enable(); 0;});}) - -#define _read_trylock(lock) ({preempt_disable();_raw_read_trylock(lock) ? \ - 1 : ({preempt_enable(); 0;});}) - -#define _write_trylock(lock) ({preempt_disable(); _raw_write_trylock(lock) ? \ - 1 : ({preempt_enable(); 0;});}) - -#define _spin_trylock_bh(lock) ({preempt_disable(); local_bh_disable(); \ - _raw_spin_trylock(lock) ? \ - 1 : ({preempt_enable_no_resched(); local_bh_enable(); 0;});}) - -#define _spin_lock(lock) \ -do { \ - preempt_disable(); \ - _raw_spin_lock(lock); \ - __acquire(lock); \ -} while(0) - -#define _write_lock(lock) \ -do { \ - preempt_disable(); \ - _raw_write_lock(lock); \ - __acquire(lock); \ -} while(0) - -#define _read_lock(lock) \ -do { \ - preempt_disable(); \ - _raw_read_lock(lock); \ - __acquire(lock); \ -} while(0) - -#define _spin_unlock(lock) \ -do { \ - _raw_spin_unlock(lock); \ - preempt_enable(); \ - __release(lock); \ -} while (0) - -#define _write_unlock(lock) \ -do { \ - _raw_write_unlock(lock); \ - preempt_enable(); \ - __release(lock); \ -} while(0) - -#define _read_unlock(lock) \ -do { \ - _raw_read_unlock(lock); \ - preempt_enable(); \ - __release(lock); \ -} while(0) - -#define _spin_lock_irqsave(lock, flags) \ -do { \ - local_irq_save(flags); \ - preempt_disable(); \ - _raw_spin_lock(lock); \ - __acquire(lock); \ -} while (0) - -#define _spin_lock_irq(lock) \ -do { \ - local_irq_disable(); \ - preempt_disable(); \ - _raw_spin_lock(lock); \ - __acquire(lock); \ -} while (0) - -#define _spin_lock_bh(lock) \ -do { \ - local_bh_disable(); \ - preempt_disable(); \ - _raw_spin_lock(lock); \ - __acquire(lock); \ -} while (0) - -#define _read_lock_irqsave(lock, flags) \ -do { \ - local_irq_save(flags); \ - preempt_disable(); \ - _raw_read_lock(lock); \ - __acquire(lock); \ -} while (0) - -#define _read_lock_irq(lock) \ -do { \ - local_irq_disable(); \ - preempt_disable(); \ - _raw_read_lock(lock); \ - __acquire(lock); \ -} while (0) - -#define _read_lock_bh(lock) \ -do { \ - local_bh_disable(); \ - preempt_disable(); \ - _raw_read_lock(lock); \ - __acquire(lock); \ -} while (0) - -#define _write_lock_irqsave(lock, flags) \ -do { \ - local_irq_save(flags); \ - preempt_disable(); \ - _raw_write_lock(lock); \ - __acquire(lock); \ -} while (0) +#ifdef CONFIG_DEBUG_SPINLOCK + extern void _raw_spin_lock(spinlock_t *lock); +#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock) + extern int _raw_spin_trylock(spinlock_t *lock); + extern void _raw_spin_unlock(spinlock_t *lock); + + extern void _raw_read_lock(rwlock_t *lock); + extern int _raw_read_trylock(rwlock_t *lock); + extern void _raw_read_unlock(rwlock_t *lock); + extern void _raw_write_lock(rwlock_t *lock); + extern int _raw_write_trylock(rwlock_t *lock); + extern void _raw_write_unlock(rwlock_t *lock); +#else +# define _raw_spin_unlock(lock) __raw_spin_unlock(&(lock)->raw_lock) +# define _raw_spin_trylock(lock) __raw_spin_trylock(&(lock)->raw_lock) +# define _raw_spin_lock(lock) __raw_spin_lock(&(lock)->raw_lock) +# define _raw_spin_lock_flags(lock, flags) \ + __raw_spin_lock_flags(&(lock)->raw_lock, *(flags)) +# define _raw_read_lock(rwlock) __raw_read_lock(&(rwlock)->raw_lock) +# define _raw_write_lock(rwlock) __raw_write_lock(&(rwlock)->raw_lock) +# define _raw_read_unlock(rwlock) __raw_read_unlock(&(rwlock)->raw_lock) +# define _raw_write_unlock(rwlock) __raw_write_unlock(&(rwlock)->raw_lock) +# define _raw_read_trylock(rwlock) __raw_read_trylock(&(rwlock)->raw_lock) +# define _raw_write_trylock(rwlock) __raw_write_trylock(&(rwlock)->raw_lock) +#endif -#define _write_lock_irq(lock) \ -do { \ - local_irq_disable(); \ - preempt_disable(); \ - _raw_write_lock(lock); \ - __acquire(lock); \ -} while (0) - -#define _write_lock_bh(lock) \ -do { \ - local_bh_disable(); \ - preempt_disable(); \ - _raw_write_lock(lock); \ - __acquire(lock); \ -} while (0) - -#define _spin_unlock_irqrestore(lock, flags) \ -do { \ - _raw_spin_unlock(lock); \ - local_irq_restore(flags); \ - preempt_enable(); \ - __release(lock); \ -} while (0) - -#define _spin_unlock_irq(lock) \ -do { \ - _raw_spin_unlock(lock); \ - local_irq_enable(); \ - preempt_enable(); \ - __release(lock); \ -} while (0) - -#define _spin_unlock_bh(lock) \ -do { \ - _raw_spin_unlock(lock); \ - preempt_enable_no_resched(); \ - local_bh_enable(); \ - __release(lock); \ -} while (0) - -#define _write_unlock_bh(lock) \ -do { \ - _raw_write_unlock(lock); \ - preempt_enable_no_resched(); \ - local_bh_enable(); \ - __release(lock); \ -} while (0) - -#define _read_unlock_irqrestore(lock, flags) \ -do { \ - _raw_read_unlock(lock); \ - local_irq_restore(flags); \ - preempt_enable(); \ - __release(lock); \ -} while (0) - -#define _write_unlock_irqrestore(lock, flags) \ -do { \ - _raw_write_unlock(lock); \ - local_irq_restore(flags); \ - preempt_enable(); \ - __release(lock); \ -} while (0) - -#define _read_unlock_irq(lock) \ -do { \ - _raw_read_unlock(lock); \ - local_irq_enable(); \ - preempt_enable(); \ - __release(lock); \ -} while (0) - -#define _read_unlock_bh(lock) \ -do { \ - _raw_read_unlock(lock); \ - preempt_enable_no_resched(); \ - local_bh_enable(); \ - __release(lock); \ -} while (0) - -#define _write_unlock_irq(lock) \ -do { \ - _raw_write_unlock(lock); \ - local_irq_enable(); \ - preempt_enable(); \ - __release(lock); \ -} while (0) - -#endif /* !SMP */ +#define read_can_lock(rwlock) __raw_read_can_lock(&(rwlock)->raw_lock) +#define write_can_lock(rwlock) __raw_write_can_lock(&(rwlock)->raw_lock) /* * Define the various spin_lock and rw_lock methods. Note we define these * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various * methods are defined as nops in the case they are not required. */ -#define spin_trylock(lock) __cond_lock(_spin_trylock(lock)) -#define read_trylock(lock) __cond_lock(_read_trylock(lock)) -#define write_trylock(lock) __cond_lock(_write_trylock(lock)) +#define spin_trylock(lock) __cond_lock(_spin_trylock(lock)) +#define read_trylock(lock) __cond_lock(_read_trylock(lock)) +#define write_trylock(lock) __cond_lock(_write_trylock(lock)) -#define spin_lock(lock) _spin_lock(lock) -#define write_lock(lock) _write_lock(lock) -#define read_lock(lock) _read_lock(lock) +#define spin_lock(lock) _spin_lock(lock) +#define write_lock(lock) _write_lock(lock) +#define read_lock(lock) _read_lock(lock) -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) #define spin_lock_irqsave(lock, flags) flags = _spin_lock_irqsave(lock) #define read_lock_irqsave(lock, flags) flags = _read_lock_irqsave(lock) #define write_lock_irqsave(lock, flags) flags = _write_lock_irqsave(lock) @@ -470,137 +171,59 @@ do { \ #define write_lock_irq(lock) _write_lock_irq(lock) #define write_lock_bh(lock) _write_lock_bh(lock) -#define spin_unlock(lock) _spin_unlock(lock) -#define write_unlock(lock) _write_unlock(lock) -#define read_unlock(lock) _read_unlock(lock) +#define spin_unlock(lock) _spin_unlock(lock) +#define write_unlock(lock) _write_unlock(lock) +#define read_unlock(lock) _read_unlock(lock) -#define spin_unlock_irqrestore(lock, flags) _spin_unlock_irqrestore(lock, flags) +#define spin_unlock_irqrestore(lock, flags) \ + _spin_unlock_irqrestore(lock, flags) #define spin_unlock_irq(lock) _spin_unlock_irq(lock) #define spin_unlock_bh(lock) _spin_unlock_bh(lock) -#define read_unlock_irqrestore(lock, flags) _read_unlock_irqrestore(lock, flags) -#define read_unlock_irq(lock) _read_unlock_irq(lock) -#define read_unlock_bh(lock) _read_unlock_bh(lock) +#define read_unlock_irqrestore(lock, flags) \ + _read_unlock_irqrestore(lock, flags) +#define read_unlock_irq(lock) _read_unlock_irq(lock) +#define read_unlock_bh(lock) _read_unlock_bh(lock) -#define write_unlock_irqrestore(lock, flags) _write_unlock_irqrestore(lock, flags) -#define write_unlock_irq(lock) _write_unlock_irq(lock) -#define write_unlock_bh(lock) _write_unlock_bh(lock) +#define write_unlock_irqrestore(lock, flags) \ + _write_unlock_irqrestore(lock, flags) +#define write_unlock_irq(lock) _write_unlock_irq(lock) +#define write_unlock_bh(lock) _write_unlock_bh(lock) -#define spin_trylock_bh(lock) __cond_lock(_spin_trylock_bh(lock)) +#define spin_trylock_bh(lock) __cond_lock(_spin_trylock_bh(lock)) #define spin_trylock_irq(lock) \ ({ \ local_irq_disable(); \ _spin_trylock(lock) ? \ - 1 : ({local_irq_enable(); 0; }); \ + 1 : ({ local_irq_enable(); 0; }); \ }) #define spin_trylock_irqsave(lock, flags) \ ({ \ local_irq_save(flags); \ _spin_trylock(lock) ? \ - 1 : ({local_irq_restore(flags); 0;}); \ + 1 : ({ local_irq_restore(flags); 0; }); \ }) -#ifdef CONFIG_LOCKMETER -extern void _metered_spin_lock (spinlock_t *lock); -extern void _metered_spin_unlock (spinlock_t *lock); -extern int _metered_spin_trylock(spinlock_t *lock); -extern void _metered_read_lock (rwlock_t *lock); -extern void _metered_read_unlock (rwlock_t *lock); -extern void _metered_write_lock (rwlock_t *lock); -extern void _metered_write_unlock (rwlock_t *lock); -extern int _metered_read_trylock (rwlock_t *lock); -extern int _metered_write_trylock(rwlock_t *lock); -#endif - -/* "lock on reference count zero" */ -#ifndef ATOMIC_DEC_AND_LOCK -#include <asm/atomic.h> -extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); -#endif - -#define atomic_dec_and_lock(atomic,lock) __cond_lock(_atomic_dec_and_lock(atomic,lock)) - -/* - * bit-based spin_lock() - * - * Don't use this unless you really need to: spin_lock() and spin_unlock() - * are significantly faster. - */ -static inline void bit_spin_lock(int bitnum, unsigned long *addr) -{ - /* - * Assuming the lock is uncontended, this never enters - * the body of the outer loop. If it is contended, then - * within the inner loop a non-atomic test is used to - * busywait with less bus contention for a good time to - * attempt to acquire the lock bit. - */ - preempt_disable(); -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - while (test_and_set_bit(bitnum, addr)) { - while (test_bit(bitnum, addr)) { - preempt_enable(); - cpu_relax(); - preempt_disable(); - } - } -#endif - __acquire(bitlock); -} - /* - * Return true if it was acquired + * Pull the atomic_t declaration: + * (asm-mips/atomic.h needs above definitions) */ -static inline int bit_spin_trylock(int bitnum, unsigned long *addr) -{ - preempt_disable(); -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - if (test_and_set_bit(bitnum, addr)) { - preempt_enable(); - return 0; - } -#endif - __acquire(bitlock); - return 1; -} - -/* - * bit-based spin_unlock() - */ -static inline void bit_spin_unlock(int bitnum, unsigned long *addr) -{ -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - BUG_ON(!test_bit(bitnum, addr)); - smp_mb__before_clear_bit(); - clear_bit(bitnum, addr); -#endif - preempt_enable(); - __release(bitlock); -} - -/* - * Return true if the lock is held. +#include <asm/atomic.h> +/** + * atomic_dec_and_lock - lock on reaching reference count zero + * @atomic: the atomic counter + * @lock: the spinlock in question */ -static inline int bit_spin_is_locked(int bitnum, unsigned long *addr) -{ -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - return test_bit(bitnum, addr); -#elif defined CONFIG_PREEMPT - return preempt_count(); -#else - return 1; -#endif -} - -#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED -#define DEFINE_RWLOCK(x) rwlock_t x = RW_LOCK_UNLOCKED +extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); +#define atomic_dec_and_lock(atomic, lock) \ + __cond_lock(_atomic_dec_and_lock(atomic, lock)) /** * spin_can_lock - would spin_trylock() succeed? * @lock: the spinlock in question. */ -#define spin_can_lock(lock) (!spin_is_locked(lock)) +#define spin_can_lock(lock) (!spin_is_locked(lock)) #endif /* __LINUX_SPINLOCK_H */ diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h new file mode 100644 index 0000000000000..78e6989ffb542 --- /dev/null +++ b/include/linux/spinlock_api_smp.h @@ -0,0 +1,57 @@ +#ifndef __LINUX_SPINLOCK_API_SMP_H +#define __LINUX_SPINLOCK_API_SMP_H + +#ifndef __LINUX_SPINLOCK_H +# error "please don't include this file directly" +#endif + +/* + * include/linux/spinlock_api_smp.h + * + * spinlock API declarations on SMP (and debug) + * (implemented in kernel/spinlock.c) + * + * portions Copyright 2005, Red Hat, Inc., Ingo Molnar + * Released under the General Public License (GPL). + */ + +int in_lock_functions(unsigned long addr); + +#define assert_spin_locked(x) BUG_ON(!spin_is_locked(x)) + +void __lockfunc _spin_lock(spinlock_t *lock) __acquires(spinlock_t); +void __lockfunc _read_lock(rwlock_t *lock) __acquires(rwlock_t); +void __lockfunc _write_lock(rwlock_t *lock) __acquires(rwlock_t); +void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(spinlock_t); +void __lockfunc _read_lock_bh(rwlock_t *lock) __acquires(rwlock_t); +void __lockfunc _write_lock_bh(rwlock_t *lock) __acquires(rwlock_t); +void __lockfunc _spin_lock_irq(spinlock_t *lock) __acquires(spinlock_t); +void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(rwlock_t); +void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(rwlock_t); +unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) + __acquires(spinlock_t); +unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) + __acquires(rwlock_t); +unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) + __acquires(rwlock_t); +int __lockfunc _spin_trylock(spinlock_t *lock); +int __lockfunc _read_trylock(rwlock_t *lock); +int __lockfunc _write_trylock(rwlock_t *lock); +int __lockfunc _spin_trylock_bh(spinlock_t *lock); +void __lockfunc _spin_unlock(spinlock_t *lock) __releases(spinlock_t); +void __lockfunc _read_unlock(rwlock_t *lock) __releases(rwlock_t); +void __lockfunc _write_unlock(rwlock_t *lock) __releases(rwlock_t); +void __lockfunc _spin_unlock_bh(spinlock_t *lock) __releases(spinlock_t); +void __lockfunc _read_unlock_bh(rwlock_t *lock) __releases(rwlock_t); +void __lockfunc _write_unlock_bh(rwlock_t *lock) __releases(rwlock_t); +void __lockfunc _spin_unlock_irq(spinlock_t *lock) __releases(spinlock_t); +void __lockfunc _read_unlock_irq(rwlock_t *lock) __releases(rwlock_t); +void __lockfunc _write_unlock_irq(rwlock_t *lock) __releases(rwlock_t); +void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) + __releases(spinlock_t); +void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) + __releases(rwlock_t); +void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) + __releases(rwlock_t); + +#endif /* __LINUX_SPINLOCK_API_SMP_H */ diff --git a/include/linux/spinlock_api_up.h b/include/linux/spinlock_api_up.h new file mode 100644 index 0000000000000..cd81cee566f4a --- /dev/null +++ b/include/linux/spinlock_api_up.h @@ -0,0 +1,80 @@ +#ifndef __LINUX_SPINLOCK_API_UP_H +#define __LINUX_SPINLOCK_API_UP_H + +#ifndef __LINUX_SPINLOCK_H +# error "please don't include this file directly" +#endif + +/* + * include/linux/spinlock_api_up.h + * + * spinlock API implementation on UP-nondebug (inlined implementation) + * + * portions Copyright 2005, Red Hat, Inc., Ingo Molnar + * Released under the General Public License (GPL). + */ + +#define in_lock_functions(ADDR) 0 + +#define assert_spin_locked(lock) do { (void)(lock); } while (0) + +/* + * In the UP-nondebug case there's no real locking going on, so the + * only thing we have to do is to keep the preempt counts and irq + * flags straight, to supress compiler warnings of unused lock + * variables, and to add the proper checker annotations: + */ +#define __LOCK(lock) \ + do { preempt_disable(); __acquire(lock); (void)(lock); } while (0) + +#define __LOCK_BH(lock) \ + do { local_bh_disable(); __LOCK(lock); } while (0) + +#define __LOCK_IRQ(lock) \ + do { local_irq_disable(); __LOCK(lock); } while (0) + +#define __LOCK_IRQSAVE(lock, flags) \ + do { local_irq_save(flags); __LOCK(lock); } while (0) + +#define __UNLOCK(lock) \ + do { preempt_enable(); __release(lock); (void)(lock); } while (0) + +#define __UNLOCK_BH(lock) \ + do { preempt_enable_no_resched(); local_bh_enable(); __release(lock); (void)(lock); } while (0) + +#define __UNLOCK_IRQ(lock) \ + do { local_irq_enable(); __UNLOCK(lock); } while (0) + +#define __UNLOCK_IRQRESTORE(lock, flags) \ + do { local_irq_restore(flags); __UNLOCK(lock); } while (0) + +#define _spin_lock(lock) __LOCK(lock) +#define _read_lock(lock) __LOCK(lock) +#define _write_lock(lock) __LOCK(lock) +#define _spin_lock_bh(lock) __LOCK_BH(lock) +#define _read_lock_bh(lock) __LOCK_BH(lock) +#define _write_lock_bh(lock) __LOCK_BH(lock) +#define _spin_lock_irq(lock) __LOCK_IRQ(lock) +#define _read_lock_irq(lock) __LOCK_IRQ(lock) +#define _write_lock_irq(lock) __LOCK_IRQ(lock) +#define _spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) +#define _read_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) +#define _write_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) +#define _spin_trylock(lock) ({ __LOCK(lock); 1; }) +#define _read_trylock(lock) ({ __LOCK(lock); 1; }) +#define _write_trylock(lock) ({ __LOCK(lock); 1; }) +#define _spin_trylock_bh(lock) ({ __LOCK_BH(lock); 1; }) +#define _spin_unlock(lock) __UNLOCK(lock) +#define _read_unlock(lock) __UNLOCK(lock) +#define _write_unlock(lock) __UNLOCK(lock) +#define _spin_unlock_bh(lock) __UNLOCK_BH(lock) +#define _write_unlock_bh(lock) __UNLOCK_BH(lock) +#define _read_unlock_bh(lock) __UNLOCK_BH(lock) +#define _spin_unlock_irq(lock) __UNLOCK_IRQ(lock) +#define _read_unlock_irq(lock) __UNLOCK_IRQ(lock) +#define _write_unlock_irq(lock) __UNLOCK_IRQ(lock) +#define _spin_unlock_irqrestore(lock, flags) __UNLOCK_IRQRESTORE(lock, flags) +#define _read_unlock_irqrestore(lock, flags) __UNLOCK_IRQRESTORE(lock, flags) +#define _write_unlock_irqrestore(lock, flags) __UNLOCK_IRQRESTORE(lock, flags) + +#endif /* __LINUX_SPINLOCK_API_UP_H */ diff --git a/include/linux/spinlock_types.h b/include/linux/spinlock_types.h new file mode 100644 index 0000000000000..9cb51e0703909 --- /dev/null +++ b/include/linux/spinlock_types.h @@ -0,0 +1,67 @@ +#ifndef __LINUX_SPINLOCK_TYPES_H +#define __LINUX_SPINLOCK_TYPES_H + +/* + * include/linux/spinlock_types.h - generic spinlock type definitions + * and initializers + * + * portions Copyright 2005, Red Hat, Inc., Ingo Molnar + * Released under the General Public License (GPL). + */ + +#if defined(CONFIG_SMP) +# include <asm/spinlock_types.h> +#else +# include <linux/spinlock_types_up.h> +#endif + +typedef struct { + raw_spinlock_t raw_lock; +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) + unsigned int break_lock; +#endif +#ifdef CONFIG_DEBUG_SPINLOCK + unsigned int magic, owner_cpu; + void *owner; +#endif +} spinlock_t; + +#define SPINLOCK_MAGIC 0xdead4ead + +typedef struct { + raw_rwlock_t raw_lock; +#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) + unsigned int break_lock; +#endif +#ifdef CONFIG_DEBUG_SPINLOCK + unsigned int magic, owner_cpu; + void *owner; +#endif +} rwlock_t; + +#define RWLOCK_MAGIC 0xdeaf1eed + +#define SPINLOCK_OWNER_INIT ((void *)-1L) + +#ifdef CONFIG_DEBUG_SPINLOCK +# define SPIN_LOCK_UNLOCKED \ + (spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED, \ + .magic = SPINLOCK_MAGIC, \ + .owner = SPINLOCK_OWNER_INIT, \ + .owner_cpu = -1 } +#define RW_LOCK_UNLOCKED \ + (rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED, \ + .magic = RWLOCK_MAGIC, \ + .owner = SPINLOCK_OWNER_INIT, \ + .owner_cpu = -1 } +#else +# define SPIN_LOCK_UNLOCKED \ + (spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED } +#define RW_LOCK_UNLOCKED \ + (rwlock_t) { .raw_lock = __RAW_RW_LOCK_UNLOCKED } +#endif + +#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED +#define DEFINE_RWLOCK(x) rwlock_t x = RW_LOCK_UNLOCKED + +#endif /* __LINUX_SPINLOCK_TYPES_H */ diff --git a/include/linux/spinlock_types_up.h b/include/linux/spinlock_types_up.h new file mode 100644 index 0000000000000..def2d173a8db0 --- /dev/null +++ b/include/linux/spinlock_types_up.h @@ -0,0 +1,51 @@ +#ifndef __LINUX_SPINLOCK_TYPES_UP_H +#define __LINUX_SPINLOCK_TYPES_UP_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +/* + * include/linux/spinlock_types_up.h - spinlock type definitions for UP + * + * portions Copyright 2005, Red Hat, Inc., Ingo Molnar + * Released under the General Public License (GPL). + */ + +#ifdef CONFIG_DEBUG_SPINLOCK + +typedef struct { + volatile unsigned int slock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 1 } + +#else + +/* + * All gcc 2.95 versions and early versions of 2.96 have a nasty bug + * with empty initializers. + */ +#if (__GNUC__ > 2) +typedef struct { } raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { } +#else +typedef struct { int gcc_is_buggy; } raw_spinlock_t; +#define __RAW_SPIN_LOCK_UNLOCKED (raw_spinlock_t) { 0 } +#endif + +#endif + +#if (__GNUC__ > 2) +typedef struct { + /* no debug version on UP */ +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { } +#else +typedef struct { int gcc_is_buggy; } raw_rwlock_t; +#define __RAW_RW_LOCK_UNLOCKED (raw_rwlock_t) { 0 } +#endif + +#endif /* __LINUX_SPINLOCK_TYPES_UP_H */ diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h new file mode 100644 index 0000000000000..31accf2f0b137 --- /dev/null +++ b/include/linux/spinlock_up.h @@ -0,0 +1,74 @@ +#ifndef __LINUX_SPINLOCK_UP_H +#define __LINUX_SPINLOCK_UP_H + +#ifndef __LINUX_SPINLOCK_H +# error "please don't include this file directly" +#endif + +/* + * include/linux/spinlock_up.h - UP-debug version of spinlocks. + * + * portions Copyright 2005, Red Hat, Inc., Ingo Molnar + * Released under the General Public License (GPL). + * + * In the debug case, 1 means unlocked, 0 means locked. (the values + * are inverted, to catch initialization bugs) + * + * No atomicity anywhere, we are on UP. + */ + +#ifdef CONFIG_DEBUG_SPINLOCK + +#define __raw_spin_is_locked(x) ((x)->slock == 0) + +static inline void __raw_spin_lock(raw_spinlock_t *lock) +{ + lock->slock = 0; +} + +static inline void +__raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags) +{ + local_irq_save(flags); + lock->slock = 0; +} + +static inline int __raw_spin_trylock(raw_spinlock_t *lock) +{ + char oldval = lock->slock; + + lock->slock = 0; + + return oldval > 0; +} + +static inline void __raw_spin_unlock(raw_spinlock_t *lock) +{ + lock->slock = 1; +} + +/* + * Read-write spinlocks. No debug version. + */ +#define __raw_read_lock(lock) do { (void)(lock); } while (0) +#define __raw_write_lock(lock) do { (void)(lock); } while (0) +#define __raw_read_trylock(lock) ({ (void)(lock); 1; }) +#define __raw_write_trylock(lock) ({ (void)(lock); 1; }) +#define __raw_read_unlock(lock) do { (void)(lock); } while (0) +#define __raw_write_unlock(lock) do { (void)(lock); } while (0) + +#else /* DEBUG_SPINLOCK */ +#define __raw_spin_is_locked(lock) ((void)(lock), 0) +/* for sched.c and kernel_lock.c: */ +# define __raw_spin_lock(lock) do { (void)(lock); } while (0) +# define __raw_spin_unlock(lock) do { (void)(lock); } while (0) +# define __raw_spin_trylock(lock) ({ (void)(lock); 1; }) +#endif /* DEBUG_SPINLOCK */ + +#define __raw_read_can_lock(lock) (((void)(lock), 1)) +#define __raw_write_can_lock(lock) (((void)(lock), 1)) + +#define __raw_spin_unlock_wait(lock) \ + do { cpu_relax(); } while (__raw_spin_is_locked(lock)) + +#endif /* __LINUX_SPINLOCK_UP_H */ diff --git a/kernel/Makefile b/kernel/Makefile index 8d57a2f1226ba..ff4dc02ce1702 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -12,6 +12,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o obj-$(CONFIG_SMP) += cpu.o spinlock.o +obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KALLSYMS) += kallsyms.o diff --git a/kernel/sched.c b/kernel/sched.c index 2632b812cf24a..15db82116e194 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1511,6 +1511,10 @@ static inline void finish_task_switch(runqueue_t *rq, task_t *prev) * Manfred Spraul <manfred@colorfullife.com> */ prev_task_flags = prev->flags; +#ifdef CONFIG_DEBUG_SPINLOCK + /* this is a valid case when another task releases the spinlock */ + rq->lock.owner = current; +#endif finish_arch_switch(prev); finish_lock_switch(rq, prev); if (mm) diff --git a/kernel/spinlock.c b/kernel/spinlock.c index 0c3f9d8bbe17b..0375fcd5921df 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -3,7 +3,10 @@ * * Author: Zwane Mwaikambo <zwane@fsmlabs.com> * - * Copyright (2004) Ingo Molnar + * Copyright (2004, 2005) Ingo Molnar + * + * This file contains the spinlock/rwlock implementations for the + * SMP and the DEBUG_SPINLOCK cases. (UP-nondebug inlines them) */ #include <linux/config.h> @@ -17,12 +20,12 @@ * Generic declaration of the raw read_trylock() function, * architectures are supposed to optimize this: */ -int __lockfunc generic_raw_read_trylock(rwlock_t *lock) +int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock) { - _raw_read_lock(lock); + __raw_read_lock(lock); return 1; } -EXPORT_SYMBOL(generic_raw_read_trylock); +EXPORT_SYMBOL(generic__raw_read_trylock); int __lockfunc _spin_trylock(spinlock_t *lock) { @@ -57,7 +60,7 @@ int __lockfunc _write_trylock(rwlock_t *lock) } EXPORT_SYMBOL(_write_trylock); -#ifndef CONFIG_PREEMPT +#if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) void __lockfunc _read_lock(rwlock_t *lock) { @@ -72,7 +75,7 @@ unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) local_irq_save(flags); preempt_disable(); - _raw_spin_lock_flags(lock, flags); + _raw_spin_lock_flags(lock, &flags); return flags; } EXPORT_SYMBOL(_spin_lock_irqsave); diff --git a/lib/Makefile b/lib/Makefile index d9c38ba05e7bc..44a46750690ae 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -16,6 +16,7 @@ CFLAGS_kobject.o += -DDEBUG CFLAGS_kobject_uevent.o += -DDEBUG endif +obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o diff --git a/lib/dec_and_lock.c b/lib/dec_and_lock.c index 6658d81e18365..2377af057d099 100644 --- a/lib/dec_and_lock.c +++ b/lib/dec_and_lock.c @@ -25,8 +25,6 @@ * this is trivially done efficiently using a load-locked * store-conditional approach, for example. */ - -#ifndef ATOMIC_DEC_AND_LOCK int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { spin_lock(lock); @@ -37,4 +35,3 @@ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) } EXPORT_SYMBOL(_atomic_dec_and_lock); -#endif diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c index bd2bc5d887b81..cb5490ec00f20 100644 --- a/lib/kernel_lock.c +++ b/lib/kernel_lock.c @@ -177,8 +177,7 @@ static inline void __lock_kernel(void) static inline void __unlock_kernel(void) { - _raw_spin_unlock(&kernel_flag); - preempt_enable(); + spin_unlock(&kernel_flag); } /* diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c new file mode 100644 index 0000000000000..906ad101eab3c --- /dev/null +++ b/lib/spinlock_debug.c @@ -0,0 +1,257 @@ +/* + * Copyright 2005, Red Hat, Inc., Ingo Molnar + * Released under the General Public License (GPL). + * + * This file contains the spinlock/rwlock implementations for + * DEBUG_SPINLOCK. + */ + +#include <linux/config.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/delay.h> + +static void spin_bug(spinlock_t *lock, const char *msg) +{ + static long print_once = 1; + struct task_struct *owner = NULL; + + if (xchg(&print_once, 0)) { + if (lock->owner && lock->owner != SPINLOCK_OWNER_INIT) + owner = lock->owner; + printk("BUG: spinlock %s on CPU#%d, %s/%d\n", + msg, smp_processor_id(), current->comm, current->pid); + printk(" lock: %p, .magic: %08x, .owner: %s/%d, .owner_cpu: %d\n", + lock, lock->magic, + owner ? owner->comm : "<none>", + owner ? owner->pid : -1, + lock->owner_cpu); + dump_stack(); +#ifdef CONFIG_SMP + /* + * We cannot continue on SMP: + */ +// panic("bad locking"); +#endif + } +} + +#define SPIN_BUG_ON(cond, lock, msg) if (unlikely(cond)) spin_bug(lock, msg) + +static inline void debug_spin_lock_before(spinlock_t *lock) +{ + SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic"); + SPIN_BUG_ON(lock->owner == current, lock, "recursion"); + SPIN_BUG_ON(lock->owner_cpu == raw_smp_processor_id(), + lock, "cpu recursion"); +} + +static inline void debug_spin_lock_after(spinlock_t *lock) +{ + lock->owner_cpu = raw_smp_processor_id(); + lock->owner = current; +} + +static inline void debug_spin_unlock(spinlock_t *lock) +{ + SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic"); + SPIN_BUG_ON(!spin_is_locked(lock), lock, "already unlocked"); + SPIN_BUG_ON(lock->owner != current, lock, "wrong owner"); + SPIN_BUG_ON(lock->owner_cpu != raw_smp_processor_id(), + lock, "wrong CPU"); + lock->owner = SPINLOCK_OWNER_INIT; + lock->owner_cpu = -1; +} + +static void __spin_lock_debug(spinlock_t *lock) +{ + int print_once = 1; + u64 i; + + for (;;) { + for (i = 0; i < loops_per_jiffy * HZ; i++) { + cpu_relax(); + if (__raw_spin_trylock(&lock->raw_lock)) + return; + } + /* lockup suspected: */ + if (print_once) { + print_once = 0; + printk("BUG: spinlock lockup on CPU#%d, %s/%d, %p\n", + smp_processor_id(), current->comm, current->pid, + lock); + dump_stack(); + } + } +} + +void _raw_spin_lock(spinlock_t *lock) +{ + debug_spin_lock_before(lock); + if (unlikely(!__raw_spin_trylock(&lock->raw_lock))) + __spin_lock_debug(lock); + debug_spin_lock_after(lock); +} + +int _raw_spin_trylock(spinlock_t *lock) +{ + int ret = __raw_spin_trylock(&lock->raw_lock); + + if (ret) + debug_spin_lock_after(lock); +#ifndef CONFIG_SMP + /* + * Must not happen on UP: + */ + SPIN_BUG_ON(!ret, lock, "trylock failure on UP"); +#endif + return ret; +} + +void _raw_spin_unlock(spinlock_t *lock) +{ + debug_spin_unlock(lock); + __raw_spin_unlock(&lock->raw_lock); +} + +static void rwlock_bug(rwlock_t *lock, const char *msg) +{ + static long print_once = 1; + + if (xchg(&print_once, 0)) { + printk("BUG: rwlock %s on CPU#%d, %s/%d, %p\n", msg, + smp_processor_id(), current->comm, current->pid, lock); + dump_stack(); +#ifdef CONFIG_SMP + /* + * We cannot continue on SMP: + */ + panic("bad locking"); +#endif + } +} + +#define RWLOCK_BUG_ON(cond, lock, msg) if (unlikely(cond)) rwlock_bug(lock, msg) + +static void __read_lock_debug(rwlock_t *lock) +{ + int print_once = 1; + u64 i; + + for (;;) { + for (i = 0; i < loops_per_jiffy * HZ; i++) { + cpu_relax(); + if (__raw_read_trylock(&lock->raw_lock)) + return; + } + /* lockup suspected: */ + if (print_once) { + print_once = 0; + printk("BUG: read-lock lockup on CPU#%d, %s/%d, %p\n", + smp_processor_id(), current->comm, current->pid, + lock); + dump_stack(); + } + } +} + +void _raw_read_lock(rwlock_t *lock) +{ + RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); + if (unlikely(!__raw_read_trylock(&lock->raw_lock))) + __read_lock_debug(lock); +} + +int _raw_read_trylock(rwlock_t *lock) +{ + int ret = __raw_read_trylock(&lock->raw_lock); + +#ifndef CONFIG_SMP + /* + * Must not happen on UP: + */ + RWLOCK_BUG_ON(!ret, lock, "trylock failure on UP"); +#endif + return ret; +} + +void _raw_read_unlock(rwlock_t *lock) +{ + RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); + __raw_read_unlock(&lock->raw_lock); +} + +static inline void debug_write_lock_before(rwlock_t *lock) +{ + RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); + RWLOCK_BUG_ON(lock->owner == current, lock, "recursion"); + RWLOCK_BUG_ON(lock->owner_cpu == raw_smp_processor_id(), + lock, "cpu recursion"); +} + +static inline void debug_write_lock_after(rwlock_t *lock) +{ + lock->owner_cpu = raw_smp_processor_id(); + lock->owner = current; +} + +static inline void debug_write_unlock(rwlock_t *lock) +{ + RWLOCK_BUG_ON(lock->magic != RWLOCK_MAGIC, lock, "bad magic"); + RWLOCK_BUG_ON(lock->owner != current, lock, "wrong owner"); + RWLOCK_BUG_ON(lock->owner_cpu != raw_smp_processor_id(), + lock, "wrong CPU"); + lock->owner = SPINLOCK_OWNER_INIT; + lock->owner_cpu = -1; +} + +static void __write_lock_debug(rwlock_t *lock) +{ + int print_once = 1; + u64 i; + + for (;;) { + for (i = 0; i < loops_per_jiffy * HZ; i++) { + cpu_relax(); + if (__raw_write_trylock(&lock->raw_lock)) + return; + } + /* lockup suspected: */ + if (print_once) { + print_once = 0; + printk("BUG: write-lock lockup on CPU#%d, %s/%d, %p\n", + smp_processor_id(), current->comm, current->pid, + lock); + dump_stack(); + } + } +} + +void _raw_write_lock(rwlock_t *lock) +{ + debug_write_lock_before(lock); + if (unlikely(!__raw_write_trylock(&lock->raw_lock))) + __write_lock_debug(lock); + debug_write_lock_after(lock); +} + +int _raw_write_trylock(rwlock_t *lock) +{ + int ret = __raw_write_trylock(&lock->raw_lock); + + if (ret) + debug_write_lock_after(lock); +#ifndef CONFIG_SMP + /* + * Must not happen on UP: + */ + RWLOCK_BUG_ON(!ret, lock, "trylock failure on UP"); +#endif + return ret; +} + +void _raw_write_unlock(rwlock_t *lock) +{ + debug_write_unlock(lock); + __raw_write_unlock(&lock->raw_lock); +} -- GitLab From 4247bdc60048018b98f71228b45cfbc5f5270c86 Mon Sep 17 00:00:00 2001 From: Paul Jackson <pj@sgi.com> Date: Sat, 10 Sep 2005 00:26:06 -0700 Subject: [PATCH 347/563] [PATCH] cpuset semaphore depth check deadlock fix The cpusets-formalize-intermediate-gfp_kernel-containment patch has a deadlock problem. This patch was part of a set of four patches to make more extensive use of the cpuset 'mem_exclusive' attribute to manage kernel GFP_KERNEL memory allocations and to constrain the out-of-memory (oom) killer. A task that is changing cpusets in particular ways on a system when it is very short of free memory could double trip over the global cpuset_sem semaphore (get the lock and then deadlock trying to get it again). The second attempt to get cpuset_sem would be in the routine cpuset_zone_allowed(). This was discovered by code inspection. I can not reproduce the problem except with an artifically hacked kernel and a specialized stress test. In real life you cannot hit this unless you are manipulating cpusets, and are very unlikely to hit it unless you are rapidly modifying cpusets on a memory tight system. Even then it would be a rare occurence. If you did hit it, the task double tripping over cpuset_sem would deadlock in the kernel, and any other task also trying to manipulate cpusets would deadlock there too, on cpuset_sem. Your batch manager would be wedged solid (if it was cpuset savvy), but classic Unix shells and utilities would work well enough to reboot the system. The unusual condition that led to this bug is that unlike most semaphores, cpuset_sem _can_ be acquired while in the page allocation code, when __alloc_pages() calls cpuset_zone_allowed. So it easy to mistakenly perform the following sequence: 1) task makes system call to alter a cpuset 2) take cpuset_sem 3) try to allocate memory 4) memory allocator, via cpuset_zone_allowed, trys to take cpuset_sem 5) deadlock The reason that this is not a serious bug for most users is that almost all calls to allocate memory don't require taking cpuset_sem. Only some code paths off the beaten track require taking cpuset_sem -- which is good. Taking a global semaphore on the main code path for allocating memory would not scale well. This patch fixes this deadlock by wrapping the up() and down() calls on cpuset_sem in kernel/cpuset.c with code that tracks the nesting depth of the current task on that semaphore, and only does the real down() if the task doesn't hold the lock already, and only does the real up() if the nesting depth (number of unmatched downs) is exactly one. The previous required use of refresh_mems(), anytime that the cpuset_sem semaphore was acquired and the code executed while holding that semaphore might try to allocate memory, is no longer required. Two refresh_mems() calls were removed thanks to this. This is a good change, as failing to get all the necessary refresh_mems() calls placed was a primary source of bugs in this cpuset code. The only remaining call to refresh_mems() is made while doing a memory allocation, if certain task memory placement data needs to be updated from its cpuset, due to the cpuset having been changed behind the tasks back. Signed-off-by: Paul Jackson <pj@sgi.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/sched.h | 1 + kernel/cpuset.c | 100 +++++++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 40 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index c551e6a1447e5..8a1fcfe80fc72 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -782,6 +782,7 @@ struct task_struct { short il_next; #endif #ifdef CONFIG_CPUSETS + short cpuset_sem_nest_depth; struct cpuset *cpuset; nodemask_t mems_allowed; int cpuset_mems_generation; diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 712d02029971e..407b5f0a8c8ee 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -181,6 +181,37 @@ static struct super_block *cpuset_sb = NULL; static DECLARE_MUTEX(cpuset_sem); +/* + * The global cpuset semaphore cpuset_sem can be needed by the + * memory allocator to update a tasks mems_allowed (see the calls + * to cpuset_update_current_mems_allowed()) or to walk up the + * cpuset hierarchy to find a mem_exclusive cpuset see the calls + * to cpuset_excl_nodes_overlap()). + * + * But if the memory allocation is being done by cpuset.c code, it + * usually already holds cpuset_sem. Double tripping on a kernel + * semaphore deadlocks the current task, and any other task that + * subsequently tries to obtain the lock. + * + * Run all up's and down's on cpuset_sem through the following + * wrappers, which will detect this nested locking, and avoid + * deadlocking. + */ + +static inline void cpuset_down(struct semaphore *psem) +{ + if (current->cpuset_sem_nest_depth == 0) + down(psem); + current->cpuset_sem_nest_depth++; +} + +static inline void cpuset_up(struct semaphore *psem) +{ + current->cpuset_sem_nest_depth--; + if (current->cpuset_sem_nest_depth == 0) + up(psem); +} + /* * A couple of forward declarations required, due to cyclic reference loop: * cpuset_mkdir -> cpuset_create -> cpuset_populate_dir -> cpuset_add_file @@ -522,19 +553,10 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask) * Refresh current tasks mems_allowed and mems_generation from * current tasks cpuset. Call with cpuset_sem held. * - * Be sure to call refresh_mems() on any cpuset operation which - * (1) holds cpuset_sem, and (2) might possibly alloc memory. - * Call after obtaining cpuset_sem lock, before any possible - * allocation. Otherwise one risks trying to allocate memory - * while the task cpuset_mems_generation is not the same as - * the mems_generation in its cpuset, which would deadlock on - * cpuset_sem in cpuset_update_current_mems_allowed(). - * - * Since we hold cpuset_sem, once refresh_mems() is called, the - * test (current->cpuset_mems_generation != cs->mems_generation) - * in cpuset_update_current_mems_allowed() will remain false, - * until we drop cpuset_sem. Anyone else who would change our - * cpusets mems_generation needs to lock cpuset_sem first. + * This routine is needed to update the per-task mems_allowed + * data, within the tasks context, when it is trying to allocate + * memory (in various mm/mempolicy.c routines) and notices + * that some other task has been modifying its cpuset. */ static void refresh_mems(void) @@ -840,7 +862,7 @@ static ssize_t cpuset_common_file_write(struct file *file, const char __user *us } buffer[nbytes] = 0; /* nul-terminate */ - down(&cpuset_sem); + cpuset_down(&cpuset_sem); if (is_removed(cs)) { retval = -ENODEV; @@ -874,7 +896,7 @@ static ssize_t cpuset_common_file_write(struct file *file, const char __user *us if (retval == 0) retval = nbytes; out2: - up(&cpuset_sem); + cpuset_up(&cpuset_sem); cpuset_release_agent(pathbuf); out1: kfree(buffer); @@ -914,9 +936,9 @@ static int cpuset_sprintf_cpulist(char *page, struct cpuset *cs) { cpumask_t mask; - down(&cpuset_sem); + cpuset_down(&cpuset_sem); mask = cs->cpus_allowed; - up(&cpuset_sem); + cpuset_up(&cpuset_sem); return cpulist_scnprintf(page, PAGE_SIZE, mask); } @@ -925,9 +947,9 @@ static int cpuset_sprintf_memlist(char *page, struct cpuset *cs) { nodemask_t mask; - down(&cpuset_sem); + cpuset_down(&cpuset_sem); mask = cs->mems_allowed; - up(&cpuset_sem); + cpuset_up(&cpuset_sem); return nodelist_scnprintf(page, PAGE_SIZE, mask); } @@ -1334,8 +1356,7 @@ static long cpuset_create(struct cpuset *parent, const char *name, int mode) if (!cs) return -ENOMEM; - down(&cpuset_sem); - refresh_mems(); + cpuset_down(&cpuset_sem); cs->flags = 0; if (notify_on_release(parent)) set_bit(CS_NOTIFY_ON_RELEASE, &cs->flags); @@ -1360,14 +1381,14 @@ static long cpuset_create(struct cpuset *parent, const char *name, int mode) * will down() this new directory's i_sem and if we race with * another mkdir, we might deadlock. */ - up(&cpuset_sem); + cpuset_up(&cpuset_sem); err = cpuset_populate_dir(cs->dentry); /* If err < 0, we have a half-filled directory - oh well ;) */ return 0; err: list_del(&cs->sibling); - up(&cpuset_sem); + cpuset_up(&cpuset_sem); kfree(cs); return err; } @@ -1389,14 +1410,13 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) /* the vfs holds both inode->i_sem already */ - down(&cpuset_sem); - refresh_mems(); + cpuset_down(&cpuset_sem); if (atomic_read(&cs->count) > 0) { - up(&cpuset_sem); + cpuset_up(&cpuset_sem); return -EBUSY; } if (!list_empty(&cs->children)) { - up(&cpuset_sem); + cpuset_up(&cpuset_sem); return -EBUSY; } parent = cs->parent; @@ -1412,7 +1432,7 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) spin_unlock(&d->d_lock); cpuset_d_remove_dir(d); dput(d); - up(&cpuset_sem); + cpuset_up(&cpuset_sem); cpuset_release_agent(pathbuf); return 0; } @@ -1515,10 +1535,10 @@ void cpuset_exit(struct task_struct *tsk) if (notify_on_release(cs)) { char *pathbuf = NULL; - down(&cpuset_sem); + cpuset_down(&cpuset_sem); if (atomic_dec_and_test(&cs->count)) check_for_release(cs, &pathbuf); - up(&cpuset_sem); + cpuset_up(&cpuset_sem); cpuset_release_agent(pathbuf); } else { atomic_dec(&cs->count); @@ -1539,11 +1559,11 @@ cpumask_t cpuset_cpus_allowed(const struct task_struct *tsk) { cpumask_t mask; - down(&cpuset_sem); + cpuset_down(&cpuset_sem); task_lock((struct task_struct *)tsk); guarantee_online_cpus(tsk->cpuset, &mask); task_unlock((struct task_struct *)tsk); - up(&cpuset_sem); + cpuset_up(&cpuset_sem); return mask; } @@ -1568,9 +1588,9 @@ void cpuset_update_current_mems_allowed(void) if (!cs) return; /* task is exiting */ if (current->cpuset_mems_generation != cs->mems_generation) { - down(&cpuset_sem); + cpuset_down(&cpuset_sem); refresh_mems(); - up(&cpuset_sem); + cpuset_up(&cpuset_sem); } } @@ -1669,14 +1689,14 @@ int cpuset_zone_allowed(struct zone *z, unsigned int __nocast gfp_mask) return 0; /* Not hardwall and node outside mems_allowed: scan up cpusets */ - down(&cpuset_sem); + cpuset_down(&cpuset_sem); cs = current->cpuset; if (!cs) goto done; /* current task exiting */ cs = nearest_exclusive_ancestor(cs); allowed = node_isset(node, cs->mems_allowed); done: - up(&cpuset_sem); + cpuset_up(&cpuset_sem); return allowed; } @@ -1697,7 +1717,7 @@ int cpuset_excl_nodes_overlap(const struct task_struct *p) const struct cpuset *cs1, *cs2; /* my and p's cpuset ancestors */ int overlap = 0; /* do cpusets overlap? */ - down(&cpuset_sem); + cpuset_down(&cpuset_sem); cs1 = current->cpuset; if (!cs1) goto done; /* current task exiting */ @@ -1708,7 +1728,7 @@ int cpuset_excl_nodes_overlap(const struct task_struct *p) cs2 = nearest_exclusive_ancestor(cs2); overlap = nodes_intersects(cs1->mems_allowed, cs2->mems_allowed); done: - up(&cpuset_sem); + cpuset_up(&cpuset_sem); return overlap; } @@ -1731,7 +1751,7 @@ static int proc_cpuset_show(struct seq_file *m, void *v) return -ENOMEM; tsk = m->private; - down(&cpuset_sem); + cpuset_down(&cpuset_sem); task_lock(tsk); cs = tsk->cpuset; task_unlock(tsk); @@ -1746,7 +1766,7 @@ static int proc_cpuset_show(struct seq_file *m, void *v) seq_puts(m, buf); seq_putc(m, '\n'); out: - up(&cpuset_sem); + cpuset_up(&cpuset_sem); kfree(buf); return retval; } -- GitLab From a7482a2e7775d163aecd8c95af7bb1b8c83890cc Mon Sep 17 00:00:00 2001 From: Paul Fulghum <paulkf@microgate.com> Date: Sat, 10 Sep 2005 00:26:07 -0700 Subject: [PATCH 348/563] [PATCH] synclink_cs add statistics clear Add ability to clear statistics. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/pcmcia/synclink_cs.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 7a0c746481249..02d7f046c10ae 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/pcmcia/synclink_cs.c * - * $Id: synclink_cs.c,v 4.26 2004/08/11 19:30:02 paulkf Exp $ + * $Id: synclink_cs.c,v 4.34 2005/09/08 13:20:54 paulkf Exp $ * * Device driver for Microgate SyncLink PC Card * multiprotocol serial adapter. @@ -472,7 +472,7 @@ module_param_array(dosyncppp, int, NULL, 0); MODULE_LICENSE("GPL"); static char *driver_name = "SyncLink PC Card driver"; -static char *driver_version = "$Revision: 4.26 $"; +static char *driver_version = "$Revision: 4.34 $"; static struct tty_driver *serial_driver; @@ -1457,6 +1457,8 @@ static int startup(MGSLPC_INFO * info) info->pending_bh = 0; + memset(&info->icount, 0, sizeof(info->icount)); + init_timer(&info->tx_timer); info->tx_timer.data = (unsigned long)info; info->tx_timer.function = tx_timeout; @@ -1946,9 +1948,13 @@ static int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount) int err; if (debug_level >= DEBUG_LEVEL_INFO) printk("get_params(%s)\n", info->device_name); - COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount)); - if (err) - return -EFAULT; + if (!user_icount) { + memset(&info->icount, 0, sizeof(info->icount)); + } else { + COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); + if (err) + return -EFAULT; + } return 0; } -- GitLab From fc38ed7531eefa332c8c69ee288487860cd6b426 Mon Sep 17 00:00:00 2001 From: Con Kolivas <kernel@kolivas.org> Date: Sat, 10 Sep 2005 00:26:08 -0700 Subject: [PATCH 349/563] [PATCH] sched: run SCHED_NORMAL tasks with real time tasks on SMT siblings The hyperthread aware nice handling currently puts to sleep any non real time task when a real time task is running on its sibling cpu. This can lead to prolonged starvation by having the non real time task pegged to the cpu with load balancing not pulling that task away. Currently we force lower priority hyperthread tasks to run a percentage of time difference based on timeslice differences which is meaningless when comparing real time tasks to SCHED_NORMAL tasks. We can allow non real time tasks to run with real time tasks on the sibling up to per_cpu_gain% if we use jiffies as a counter. Cleanups and micro-optimisations to the relevant code section should make it more understandable as well. Signed-off-by: Con Kolivas <kernel@kolivas.org> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 65 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 15db82116e194..ef748e6916083 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2580,6 +2580,13 @@ void scheduler_tick(void) } #ifdef CONFIG_SCHED_SMT +static inline void wakeup_busy_runqueue(runqueue_t *rq) +{ + /* If an SMT runqueue is sleeping due to priority reasons wake it up */ + if (rq->curr == rq->idle && rq->nr_running) + resched_task(rq->idle); +} + static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq) { struct sched_domain *tmp, *sd = NULL; @@ -2613,12 +2620,7 @@ static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq) for_each_cpu_mask(i, sibling_map) { runqueue_t *smt_rq = cpu_rq(i); - /* - * If an SMT sibling task is sleeping due to priority - * reasons wake it up now. - */ - if (smt_rq->curr == smt_rq->idle && smt_rq->nr_running) - resched_task(smt_rq->idle); + wakeup_busy_runqueue(smt_rq); } for_each_cpu_mask(i, sibling_map) @@ -2672,6 +2674,10 @@ static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq) runqueue_t *smt_rq = cpu_rq(i); task_t *smt_curr = smt_rq->curr; + /* Kernel threads do not participate in dependent sleeping */ + if (!p->mm || !smt_curr->mm || rt_task(p)) + goto check_smt_task; + /* * If a user task with lower static priority than the * running task on the SMT sibling is trying to schedule, @@ -2680,21 +2686,44 @@ static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq) * task from using an unfair proportion of the * physical cpu's resources. -ck */ - if (((smt_curr->time_slice * (100 - sd->per_cpu_gain) / 100) > - task_timeslice(p) || rt_task(smt_curr)) && - p->mm && smt_curr->mm && !rt_task(p)) - ret = 1; + if (rt_task(smt_curr)) { + /* + * With real time tasks we run non-rt tasks only + * per_cpu_gain% of the time. + */ + if ((jiffies % DEF_TIMESLICE) > + (sd->per_cpu_gain * DEF_TIMESLICE / 100)) + ret = 1; + } else + if (((smt_curr->time_slice * (100 - sd->per_cpu_gain) / + 100) > task_timeslice(p))) + ret = 1; + +check_smt_task: + if ((!smt_curr->mm && smt_curr != smt_rq->idle) || + rt_task(smt_curr)) + continue; + if (!p->mm) { + wakeup_busy_runqueue(smt_rq); + continue; + } /* - * Reschedule a lower priority task on the SMT sibling, - * or wake it up if it has been put to sleep for priority - * reasons. + * Reschedule a lower priority task on the SMT sibling for + * it to be put to sleep, or wake it up if it has been put to + * sleep for priority reasons to see if it should run now. */ - if ((((p->time_slice * (100 - sd->per_cpu_gain) / 100) > - task_timeslice(smt_curr) || rt_task(p)) && - smt_curr->mm && p->mm && !rt_task(smt_curr)) || - (smt_curr == smt_rq->idle && smt_rq->nr_running)) - resched_task(smt_curr); + if (rt_task(p)) { + if ((jiffies % DEF_TIMESLICE) > + (sd->per_cpu_gain * DEF_TIMESLICE / 100)) + resched_task(smt_curr); + } else { + if ((p->time_slice * (100 - sd->per_cpu_gain) / 100) > + task_timeslice(smt_curr)) + resched_task(smt_curr); + else + wakeup_busy_runqueue(smt_rq); + } } out_unlock: for_each_cpu_mask(i, sibling_map) -- GitLab From da5a5522709a030da91932d4d4c2b179a481a8c0 Mon Sep 17 00:00:00 2001 From: "M.Baris Demiray" <baris@labristeknoloji.com> Date: Sat, 10 Sep 2005 00:26:09 -0700 Subject: [PATCH 350/563] [PATCH] sched: make idlest_group/cpu cpus_allowed-aware Add relevant checks into find_idlest_group() and find_idlest_cpu() to make them return only the groups that have allowed CPUs and allowed CPUs respectively. Signed-off-by: M.Baris Demiray <baris@labristeknoloji.com> Signed-off-by: Nick Piggin <nickpiggin@yahoo.com.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index ef748e6916083..bac23fb418f60 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -966,8 +966,11 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu) int local_group; int i; + /* Skip over this group if it has no CPUs allowed */ + if (!cpus_intersects(group->cpumask, p->cpus_allowed)) + goto nextgroup; + local_group = cpu_isset(this_cpu, group->cpumask); - /* XXX: put a cpus allowed check */ /* Tally up the load of all CPUs in the group */ avg_load = 0; @@ -992,6 +995,7 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu) min_load = avg_load; idlest = group; } +nextgroup: group = group->next; } while (group != sd->groups); @@ -1003,13 +1007,18 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu) /* * find_idlest_queue - find the idlest runqueue among the cpus in group. */ -static int find_idlest_cpu(struct sched_group *group, int this_cpu) +static int find_idlest_cpu(struct sched_group *group, + struct task_struct *p, int this_cpu) { + cpumask_t tmp; unsigned long load, min_load = ULONG_MAX; int idlest = -1; int i; - for_each_cpu_mask(i, group->cpumask) { + /* Traverse only the allowed CPUs */ + cpus_and(tmp, group->cpumask, p->cpus_allowed); + + for_each_cpu_mask(i, tmp) { load = source_load(i, 0); if (load < min_load || (load == min_load && i == this_cpu)) { @@ -1052,7 +1061,7 @@ static int sched_balance_self(int cpu, int flag) if (!group) goto nextlevel; - new_cpu = find_idlest_cpu(group, cpu); + new_cpu = find_idlest_cpu(group, t, cpu); if (new_cpu == -1 || new_cpu == cpu) goto nextlevel; -- GitLab From 95cdf3b799a481969a48d69a1a52916ad5da6694 Mon Sep 17 00:00:00 2001 From: Ingo Molnar <mingo@elte.hu> Date: Sat, 10 Sep 2005 00:26:11 -0700 Subject: [PATCH 351/563] [PATCH] sched cleanups whitespace cleanups. Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index bac23fb418f60..24eed372d2800 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -875,7 +875,7 @@ static int migrate_task(task_t *p, int dest_cpu, migration_req_t *req) * smp_call_function() if an IPI is sent by the same process we are * waiting to become inactive. */ -void wait_task_inactive(task_t * p) +void wait_task_inactive(task_t *p) { unsigned long flags; runqueue_t *rq; @@ -1007,8 +1007,8 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu) /* * find_idlest_queue - find the idlest runqueue among the cpus in group. */ -static int find_idlest_cpu(struct sched_group *group, - struct task_struct *p, int this_cpu) +static int +find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu) { cpumask_t tmp; unsigned long load, min_load = ULONG_MAX; @@ -1136,7 +1136,7 @@ static inline int wake_idle(int cpu, task_t *p) * * returns failure only if the task is already active. */ -static int try_to_wake_up(task_t * p, unsigned int state, int sync) +static int try_to_wake_up(task_t *p, unsigned int state, int sync) { int cpu, this_cpu, success = 0; unsigned long flags; @@ -1283,7 +1283,7 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync) return success; } -int fastcall wake_up_process(task_t * p) +int fastcall wake_up_process(task_t *p) { return try_to_wake_up(p, TASK_STOPPED | TASK_TRACED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0); @@ -1362,7 +1362,7 @@ void fastcall sched_fork(task_t *p, int clone_flags) * that must be done for every newly created context, then puts the task * on the runqueue and wakes it. */ -void fastcall wake_up_new_task(task_t * p, unsigned long clone_flags) +void fastcall wake_up_new_task(task_t *p, unsigned long clone_flags) { unsigned long flags; int this_cpu, cpu; @@ -1445,7 +1445,7 @@ void fastcall wake_up_new_task(task_t * p, unsigned long clone_flags) * artificially, because any timeslice recovered here * was given away by the parent in the first place.) */ -void fastcall sched_exit(task_t * p) +void fastcall sched_exit(task_t *p) { unsigned long flags; runqueue_t *rq; @@ -1766,7 +1766,8 @@ void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p, */ static inline int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu, - struct sched_domain *sd, enum idle_type idle, int *all_pinned) + struct sched_domain *sd, enum idle_type idle, + int *all_pinned) { /* * We do not migrate tasks that are: @@ -3058,7 +3059,8 @@ asmlinkage void __sched preempt_schedule_irq(void) #endif /* CONFIG_PREEMPT */ -int default_wake_function(wait_queue_t *curr, unsigned mode, int sync, void *key) +int default_wake_function(wait_queue_t *curr, unsigned mode, int sync, + void *key) { task_t *p = curr->private; return try_to_wake_up(p, mode, sync); @@ -3100,7 +3102,7 @@ static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, * @key: is directly passed to the wakeup function */ void fastcall __wake_up(wait_queue_head_t *q, unsigned int mode, - int nr_exclusive, void *key) + int nr_exclusive, void *key) { unsigned long flags; @@ -3132,7 +3134,8 @@ void fastcall __wake_up_locked(wait_queue_head_t *q, unsigned int mode) * * On UP it can prevent extra preemption. */ -void fastcall __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) +void fastcall +__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) { unsigned long flags; int sync = 1; @@ -3323,7 +3326,8 @@ void fastcall __sched interruptible_sleep_on(wait_queue_head_t *q) EXPORT_SYMBOL(interruptible_sleep_on); -long fastcall __sched interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout) +long fastcall __sched +interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout) { SLEEP_ON_VAR @@ -3542,7 +3546,8 @@ static void __setscheduler(struct task_struct *p, int policy, int prio) * @policy: new policy. * @param: structure containing the new RT priority. */ -int sched_setscheduler(struct task_struct *p, int policy, struct sched_param *param) +int sched_setscheduler(struct task_struct *p, int policy, + struct sched_param *param) { int retval; int oldprio, oldpolicy = -1; @@ -3562,7 +3567,7 @@ int sched_setscheduler(struct task_struct *p, int policy, struct sched_param *pa * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL is 0. */ if (param->sched_priority < 0 || - (p->mm && param->sched_priority > MAX_USER_RT_PRIO-1) || + (p->mm && param->sched_priority > MAX_USER_RT_PRIO-1) || (!p->mm && param->sched_priority > MAX_RT_PRIO-1)) return -EINVAL; if ((policy == SCHED_NORMAL) != (param->sched_priority == 0)) @@ -3625,7 +3630,8 @@ int sched_setscheduler(struct task_struct *p, int policy, struct sched_param *pa } EXPORT_SYMBOL_GPL(sched_setscheduler); -static int do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param) +static int +do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param) { int retval; struct sched_param lparam; @@ -3956,7 +3962,7 @@ EXPORT_SYMBOL(cond_resched); * operations here to prevent schedule() from being called twice (once via * spin_unlock(), once by hand). */ -int cond_resched_lock(spinlock_t * lock) +int cond_resched_lock(spinlock_t *lock) { int ret = 0; @@ -4139,7 +4145,7 @@ static inline struct task_struct *younger_sibling(struct task_struct *p) return list_entry(p->sibling.next,struct task_struct,sibling); } -static void show_task(task_t * p) +static void show_task(task_t *p) { task_t *relative; unsigned state; @@ -4165,7 +4171,7 @@ static void show_task(task_t * p) #endif #ifdef CONFIG_DEBUG_STACK_USAGE { - unsigned long * n = (unsigned long *) (p->thread_info+1); + unsigned long *n = (unsigned long *) (p->thread_info+1); while (!*n) n++; free = (unsigned long) n - (unsigned long)(p->thread_info+1); @@ -4374,7 +4380,7 @@ static void __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) * thread migration by bumping thread off CPU then 'pushing' onto * another runqueue. */ -static int migration_thread(void * data) +static int migration_thread(void *data) { runqueue_t *rq; int cpu = (long)data; -- GitLab From d79fc0fc6645b0cf5cd980da76942ca6d6300fa4 Mon Sep 17 00:00:00 2001 From: Ingo Molnar <mingo@elte.hu> Date: Sat, 10 Sep 2005 00:26:12 -0700 Subject: [PATCH 352/563] [PATCH] sched: TASK_NONINTERACTIVE This patch implements a task state bit (TASK_NONINTERACTIVE), which can be used by blocking points to mark the task's wait as "non-interactive". This does not mean the task will be considered a CPU-hog - the wait will simply not have an effect on the waiting task's priority - positive or negative alike. Right now only pipe_wait() will make use of it, because it's a common source of not-so-interactive waits (kernel compilation jobs, etc.). Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/pipe.c | 6 +++++- include/linux/sched.h | 1 + kernel/sched.c | 11 ++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/fs/pipe.c b/fs/pipe.c index 2c7a23dde2d83..66aa0b938d6ac 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -39,7 +39,11 @@ void pipe_wait(struct inode * inode) { DEFINE_WAIT(wait); - prepare_to_wait(PIPE_WAIT(*inode), &wait, TASK_INTERRUPTIBLE); + /* + * Pipes are system-local resources, so sleeping on them + * is considered a noninteractive wait: + */ + prepare_to_wait(PIPE_WAIT(*inode), &wait, TASK_INTERRUPTIBLE|TASK_NONINTERACTIVE); up(PIPE_SEM(*inode)); schedule(); finish_wait(PIPE_WAIT(*inode), &wait); diff --git a/include/linux/sched.h b/include/linux/sched.h index 8a1fcfe80fc72..ac70f845b5b1d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -114,6 +114,7 @@ extern unsigned long nr_iowait(void); #define TASK_TRACED 8 #define EXIT_ZOMBIE 16 #define EXIT_DEAD 32 +#define TASK_NONINTERACTIVE 64 #define __set_task_state(tsk, state_value) \ do { (tsk)->state = (state_value); } while (0) diff --git a/kernel/sched.c b/kernel/sched.c index 24eed372d2800..6da13bba3e23c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1260,6 +1260,16 @@ static int try_to_wake_up(task_t *p, unsigned int state, int sync) p->activated = -1; } + /* + * Tasks that have marked their sleep as noninteractive get + * woken up without updating their sleep average. (i.e. their + * sleep is handled in a priority-neutral manner, no priority + * boost and no penalty.) + */ + if (old_state & TASK_NONINTERACTIVE) + __activate_task(p, rq); + else + activate_task(p, rq, cpu == this_cpu); /* * Sync wakeups (i.e. those types of wakeups where the waker * has indicated that it will leave the CPU in short order) @@ -1268,7 +1278,6 @@ static int try_to_wake_up(task_t *p, unsigned int state, int sync) * the waker guarantees that the freshly woken up task is going * to be considered on this CPU.) */ - activate_task(p, rq, cpu == this_cpu); if (!sync || cpu != this_cpu) { if (TASK_PREEMPTS_CURR(p, rq)) resched_task(rq->curr); -- GitLab From 67f9a619e7460b7d07284a9d0745727a77d3ade6 Mon Sep 17 00:00:00 2001 From: Ingo Molnar <mingo@elte.hu> Date: Sat, 10 Sep 2005 00:26:16 -0700 Subject: [PATCH 353/563] [PATCH] sched: fix SMT scheduler latency bug William Weston reported unusually high scheduling latencies on his x86 HT box, on the -RT kernel. I managed to reproduce it on my HT box and the latency tracer shows the incident in action: _------=> CPU# / _-----=> irqs-off | / _----=> need-resched || / _---=> hardirq/softirq ||| / _--=> preempt-depth |||| / ||||| delay cmd pid ||||| time | caller \ / ||||| \ | / du-2803 3Dnh2 0us : __trace_start_sched_wakeup (try_to_wake_up) .............................................................. ... we are running on CPU#3, PID 2778 gets woken to CPU#1: ... .............................................................. du-2803 3Dnh2 0us : __trace_start_sched_wakeup <<...>-2778> (73 1) du-2803 3Dnh2 0us : _raw_spin_unlock (try_to_wake_up) ................................................ ... still on CPU#3, we send an IPI to CPU#1: ... ................................................ du-2803 3Dnh1 0us : resched_task (try_to_wake_up) du-2803 3Dnh1 1us : smp_send_reschedule (try_to_wake_up) du-2803 3Dnh1 1us : send_IPI_mask_bitmask (smp_send_reschedule) du-2803 3Dnh1 2us : _raw_spin_unlock_irqrestore (try_to_wake_up) ............................................... ... 1 usec later, the IPI arrives on CPU#1: ... ............................................... <idle>-0 1Dnh. 2us : smp_reschedule_interrupt (c0100c5a 0 0) So far so good, this is the normal wakeup/preemption mechanism. But here comes the scheduler anomaly on CPU#1: <idle>-0 1Dnh. 2us : preempt_schedule_irq (need_resched) <idle>-0 1Dnh. 2us : preempt_schedule_irq (need_resched) <idle>-0 1Dnh. 3us : __schedule (preempt_schedule_irq) <idle>-0 1Dnh. 3us : profile_hit (__schedule) <idle>-0 1Dnh1 3us : sched_clock (__schedule) <idle>-0 1Dnh1 4us : _raw_spin_lock_irq (__schedule) <idle>-0 1Dnh1 4us : _raw_spin_lock_irqsave (__schedule) <idle>-0 1Dnh2 5us : _raw_spin_unlock (__schedule) <idle>-0 1Dnh1 5us : preempt_schedule (__schedule) <idle>-0 1Dnh1 6us : _raw_spin_lock (__schedule) <idle>-0 1Dnh2 6us : find_next_bit (__schedule) <idle>-0 1Dnh2 6us : _raw_spin_lock (__schedule) <idle>-0 1Dnh3 7us : find_next_bit (__schedule) <idle>-0 1Dnh3 7us : find_next_bit (__schedule) <idle>-0 1Dnh3 8us : _raw_spin_unlock (__schedule) <idle>-0 1Dnh2 8us : preempt_schedule (__schedule) <idle>-0 1Dnh2 8us : find_next_bit (__schedule) <idle>-0 1Dnh2 9us : trace_stop_sched_switched (__schedule) <idle>-0 1Dnh2 9us : _raw_spin_lock (trace_stop_sched_switched) <idle>-0 1Dnh3 10us : trace_stop_sched_switched <<...>-2778> (73 8c) <idle>-0 1Dnh3 10us : _raw_spin_unlock (trace_stop_sched_switched) <idle>-0 1Dnh1 10us : _raw_spin_unlock (__schedule) <idle>-0 1Dnh. 11us : local_irq_enable_noresched (preempt_schedule_irq) <idle>-0 1Dnh. 11us < (0) we didnt pick up pid 2778! It only gets scheduled much later: <...>-2778 1Dnh2 412us : __switch_to (__schedule) <...>-2778 1Dnh2 413us : __schedule <<idle>-0> (8c 73) <...>-2778 1Dnh2 413us : _raw_spin_unlock (__schedule) <...>-2778 1Dnh1 413us : trace_stop_sched_switched (__schedule) <...>-2778 1Dnh1 414us : _raw_spin_lock (trace_stop_sched_switched) <...>-2778 1Dnh2 414us : trace_stop_sched_switched <<...>-2778> (73 1) <...>-2778 1Dnh2 414us : _raw_spin_unlock (trace_stop_sched_switched) <...>-2778 1Dnh1 415us : trace_stop_sched_switched (__schedule) the reason for this anomaly is the following code in dependent_sleeper(): /* * If a user task with lower static priority than the * running task on the SMT sibling is trying to schedule, * delay it till there is proportionately less timeslice * left of the sibling task to prevent a lower priority * task from using an unfair proportion of the * physical cpu's resources. -ck */ [...] if (((smt_curr->time_slice * (100 - sd->per_cpu_gain) / 100) > task_timeslice(p))) ret = 1; Note that in contrast to the comment above, we dont actually do the check based on static priority, we do the check based on timeslices. But timeslices go up and down, and even highprio tasks can randomly have very low timeslices (just before their next refill) and can thus be judged as 'lowprio' by the above piece of code. This condition is clearly buggy. The correct test is to check for static_prio _and_ to check for the preemption priority. Even on different static priority levels, a higher-prio interactive task should not be delayed due to a higher-static-prio CPU hog. There is a symmetric bug in the 'kick SMT sibling' code of this function as well, which can be solved in a similar way. The patch below (against the current scheduler queue in -mm) fixes both bugs. I have build and boot-tested this on x86 SMT, and nice +20 tasks still get properly throttled - so the dependent-sleeper logic is still in action. btw., these bugs pessimised the SMT scheduler because the 'delay wakeup' property was applied too liberally, so this fix is likely a throughput improvement as well. I separated out a smt_slice() function to make the code easier to read. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 6da13bba3e23c..c61ee3451a044 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2650,6 +2650,16 @@ static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq) */ } +/* + * number of 'lost' timeslices this task wont be able to fully + * utilize, if another task runs on a sibling. This models the + * slowdown effect of other tasks running on siblings: + */ +static inline unsigned long smt_slice(task_t *p, struct sched_domain *sd) +{ + return p->time_slice * (100 - sd->per_cpu_gain) / 100; +} + static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq) { struct sched_domain *tmp, *sd = NULL; @@ -2714,8 +2724,9 @@ static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq) (sd->per_cpu_gain * DEF_TIMESLICE / 100)) ret = 1; } else - if (((smt_curr->time_slice * (100 - sd->per_cpu_gain) / - 100) > task_timeslice(p))) + if (smt_curr->static_prio < p->static_prio && + !TASK_PREEMPTS_CURR(p, smt_rq) && + smt_slice(smt_curr, sd) > task_timeslice(p)) ret = 1; check_smt_task: @@ -2737,8 +2748,8 @@ static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq) (sd->per_cpu_gain * DEF_TIMESLICE / 100)) resched_task(smt_curr); } else { - if ((p->time_slice * (100 - sd->per_cpu_gain) / 100) > - task_timeslice(smt_curr)) + if (TASK_PREEMPTS_CURR(p, smt_rq) && + smt_slice(p, sd) > task_timeslice(smt_curr)) resched_task(smt_curr); else wakeup_busy_runqueue(smt_rq); -- GitLab From d6d5cfaf4551aa7713ca6ab73bb77e832602204b Mon Sep 17 00:00:00 2001 From: Nick Piggin <nickpiggin@yahoo.com.au> Date: Sat, 10 Sep 2005 00:26:16 -0700 Subject: [PATCH 354/563] [PATCH] sched: less newidle locking Similarly to the earlier change in load_balance, only lock the runqueue in load_balance_newidle if the busiest queue found has a nr_running > 1. This will reduce frequency of expensive remote runqueue lock aquisitions in the schedule() path on some workloads. Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index c61ee3451a044..930189540f3be 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2104,8 +2104,7 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, */ double_lock_balance(this_rq, busiest); nr_moved = move_tasks(this_rq, this_cpu, busiest, - imbalance, sd, idle, - &all_pinned); + imbalance, sd, idle, &all_pinned); spin_unlock(&busiest->lock); /* All tasks on this runqueue were pinned by CPU affinity */ @@ -2200,18 +2199,22 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq, BUG_ON(busiest == this_rq); - /* Attempt to move tasks */ - double_lock_balance(this_rq, busiest); - schedstat_add(sd, lb_imbalance[NEWLY_IDLE], imbalance); - nr_moved = move_tasks(this_rq, this_cpu, busiest, + + nr_moved = 0; + if (busiest->nr_running > 1) { + /* Attempt to move tasks */ + double_lock_balance(this_rq, busiest); + nr_moved = move_tasks(this_rq, this_cpu, busiest, imbalance, sd, NEWLY_IDLE, NULL); + spin_unlock(&busiest->lock); + } + if (!nr_moved) schedstat_inc(sd, lb_failed[NEWLY_IDLE]); else sd->nr_balance_failed = 0; - spin_unlock(&busiest->lock); return nr_moved; out_balanced: -- GitLab From e17224bf1d01b461ec02a60f5a9b7657a89bdd23 Mon Sep 17 00:00:00 2001 From: Nick Piggin <nickpiggin@yahoo.com.au> Date: Sat, 10 Sep 2005 00:26:18 -0700 Subject: [PATCH 355/563] [PATCH] sched: less locking During periodic load balancing, don't hold this runqueue's lock while scanning remote runqueues, which can take a non trivial amount of time especially on very large systems. Holding the runqueue lock will only help to stabilise ->nr_running, however this doesn't do much to help because tasks being woken will simply get held up on the runqueue lock, so ->nr_running would not provide a really accurate picture of runqueue load in that case anyway. What's more, ->nr_running (and possibly the cpu_load averages) of remote runqueues won't be stable anyway, so load balancing is always an inexact operation. Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 930189540f3be..8535e5c68f5b6 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2075,7 +2075,6 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, int nr_moved, all_pinned = 0; int active_balance = 0; - spin_lock(&this_rq->lock); schedstat_inc(sd, lb_cnt[idle]); group = find_busiest_group(sd, this_cpu, &imbalance, idle); @@ -2102,18 +2101,16 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, * still unbalanced. nr_moved simply stays zero, so it is * correctly treated as an imbalance. */ - double_lock_balance(this_rq, busiest); + double_rq_lock(this_rq, busiest); nr_moved = move_tasks(this_rq, this_cpu, busiest, imbalance, sd, idle, &all_pinned); - spin_unlock(&busiest->lock); + double_rq_unlock(this_rq, busiest); /* All tasks on this runqueue were pinned by CPU affinity */ if (unlikely(all_pinned)) goto out_balanced; } - spin_unlock(&this_rq->lock); - if (!nr_moved) { schedstat_inc(sd, lb_failed[idle]); sd->nr_balance_failed++; @@ -2156,8 +2153,6 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, return nr_moved; out_balanced: - spin_unlock(&this_rq->lock); - schedstat_inc(sd, lb_balanced[idle]); sd->nr_balance_failed = 0; -- GitLab From 5969fe0618051e8577316555a81a6e44b7b7d640 Mon Sep 17 00:00:00 2001 From: Nick Piggin <nickpiggin@yahoo.com.au> Date: Sat, 10 Sep 2005 00:26:19 -0700 Subject: [PATCH 356/563] [PATCH] sched: HT optimisation If an idle sibling of an HT queue encounters a busy sibling, then make higher level load balancing of the non-idle variety. Performance of multiprocessor HT systems with low numbers of tasks (generally < number of virtual CPUs) can be significantly worse than the exact same workloads when running in non-HT mode. The reason is largely due to poor scheduling behaviour. This patch improves the situation, making the performance gap far less significant on one problematic test case (tbench). Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 8535e5c68f5b6..46fdd0bb1ed6c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1906,7 +1906,7 @@ static int move_tasks(runqueue_t *this_rq, int this_cpu, runqueue_t *busiest, */ static struct sched_group * find_busiest_group(struct sched_domain *sd, int this_cpu, - unsigned long *imbalance, enum idle_type idle) + unsigned long *imbalance, enum idle_type idle, int *sd_idle) { struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups; unsigned long max_load, avg_load, total_load, this_load, total_pwr; @@ -1931,6 +1931,9 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, avg_load = 0; for_each_cpu_mask(i, group->cpumask) { + if (*sd_idle && !idle_cpu(i)) + *sd_idle = 0; + /* Bias balancing toward cpus of our domain */ if (local_group) load = target_load(i, load_idx); @@ -2074,10 +2077,14 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, unsigned long imbalance; int nr_moved, all_pinned = 0; int active_balance = 0; + int sd_idle = 0; + + if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER) + sd_idle = 1; schedstat_inc(sd, lb_cnt[idle]); - group = find_busiest_group(sd, this_cpu, &imbalance, idle); + group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle); if (!group) { schedstat_inc(sd, lb_nobusyg[idle]); goto out_balanced; @@ -2150,6 +2157,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, sd->balance_interval *= 2; } + if (!nr_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER) + return -1; return nr_moved; out_balanced: @@ -2161,6 +2170,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, (sd->balance_interval < sd->max_interval)) sd->balance_interval *= 2; + if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER) + return -1; return 0; } @@ -2178,9 +2189,13 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq, runqueue_t *busiest = NULL; unsigned long imbalance; int nr_moved = 0; + int sd_idle = 0; + + if (sd->flags & SD_SHARE_CPUPOWER) + sd_idle = 1; schedstat_inc(sd, lb_cnt[NEWLY_IDLE]); - group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE); + group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE, &sd_idle); if (!group) { schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]); goto out_balanced; @@ -2205,15 +2220,19 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq, spin_unlock(&busiest->lock); } - if (!nr_moved) + if (!nr_moved) { schedstat_inc(sd, lb_failed[NEWLY_IDLE]); - else + if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER) + return -1; + } else sd->nr_balance_failed = 0; return nr_moved; out_balanced: schedstat_inc(sd, lb_balanced[NEWLY_IDLE]); + if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER) + return -1; sd->nr_balance_failed = 0; return 0; } @@ -2338,7 +2357,10 @@ static void rebalance_tick(int this_cpu, runqueue_t *this_rq, if (j - sd->last_balance >= interval) { if (load_balance(this_cpu, this_rq, sd, idle)) { - /* We've pulled tasks over so no longer idle */ + /* We've pulled tasks over so either we're no + * longer idle, or one of our SMT siblings is + * not idle. + */ idle = NOT_IDLE; } sd->last_balance += interval; -- GitLab From 5927ad78ec75870b1bdfa65a10ad1300cd664d36 Mon Sep 17 00:00:00 2001 From: Renaud Lienhart <renaud.lienhart@free.fr> Date: Sat, 10 Sep 2005 00:26:20 -0700 Subject: [PATCH 357/563] [PATCH] sched: use cached variable in sys_sched_yield() In sys_sched_yield(), we cache current->array in the "array" variable, thus there's no need to dereference "current" again later. Signed-Off-By: Renaud Lienhart <renaud.lienhart@free.fr> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched.c b/kernel/sched.c index 46fdd0bb1ed6c..103f705b245c7 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3938,7 +3938,7 @@ asmlinkage long sys_sched_yield(void) if (rt_task(current)) target = rq->active; - if (current->array->nr_active == 1) { + if (array->nr_active == 1) { schedstat_inc(rq, yld_act_empty); if (!rq->expired->nr_active) schedstat_inc(rq, yld_both_empty); -- GitLab From fa3b6ddc3f4a8eadba52234134cdb59c28b5332d Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" <suresh.b.siddha@intel.com> Date: Sat, 10 Sep 2005 00:26:21 -0700 Subject: [PATCH 358/563] [PATCH] sched: don't kick ALB in the presence of pinned task Jack Steiner brought this issue at my OLS talk. Take a scenario where two tasks are pinned to two HT threads in a physical package. Idle packages in the system will keep kicking migration_thread on the busy package with out any success. We will run into similar scenarios in the presence of CMP/NUMA. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/kernel/sched.c b/kernel/sched.c index 103f705b245c7..1dc29dec38a9d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2125,6 +2125,16 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) { spin_lock(&busiest->lock); + + /* don't kick the migration_thread, if the curr + * task on busiest cpu can't be moved to this_cpu + */ + if (!cpu_isset(this_cpu, busiest->curr->cpus_allowed)) { + spin_unlock(&busiest->lock); + all_pinned = 1; + goto out_one_pinned; + } + if (!busiest->active_balance) { busiest->active_balance = 1; busiest->push_cpu = this_cpu; @@ -2165,6 +2175,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq, schedstat_inc(sd, lb_balanced[idle]); sd->nr_balance_failed = 0; + +out_one_pinned: /* tune up the balancing interval */ if ((all_pinned && sd->balance_interval < MAX_PINNED_INTERVAL) || (sd->balance_interval < sd->max_interval)) @@ -2357,7 +2369,8 @@ static void rebalance_tick(int this_cpu, runqueue_t *this_rq, if (j - sd->last_balance >= interval) { if (load_balance(this_cpu, this_rq, sd, idle)) { - /* We've pulled tasks over so either we're no + /* + * We've pulled tasks over so either we're no * longer idle, or one of our SMT siblings is * not idle. */ -- GitLab From 0c117f1b4d14380baeed9c883f765ee023da8761 Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" <suresh.b.siddha@intel.com> Date: Sat, 10 Sep 2005 00:26:21 -0700 Subject: [PATCH 359/563] [PATCH] sched: allow the load to grow upto its cpu_power Don't pull tasks from a group if that would cause the group's total load to drop below its total cpu_power (ie. cause the group to start going idle). Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Signed-off-by: Nick Piggin <npiggin@suse.de> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 1dc29dec38a9d..dbd4490afec14 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1910,6 +1910,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, { struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups; unsigned long max_load, avg_load, total_load, this_load, total_pwr; + unsigned long max_pull; int load_idx; max_load = this_load = total_load = total_pwr = 0; @@ -1959,7 +1960,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, group = group->next; } while (group != sd->groups); - if (!busiest || this_load >= max_load) + if (!busiest || this_load >= max_load || max_load <= SCHED_LOAD_SCALE) goto out_balanced; avg_load = (SCHED_LOAD_SCALE * total_load) / total_pwr; @@ -1979,8 +1980,12 @@ find_busiest_group(struct sched_domain *sd, int this_cpu, * by pulling tasks to us. Be careful of negative numbers as they'll * appear as very large values with unsigned longs. */ + + /* Don't want to pull so many tasks that a group would go idle */ + max_pull = min(max_load - avg_load, max_load - SCHED_LOAD_SCALE); + /* How much load to actually move to equalise the imbalance */ - *imbalance = min((max_load - avg_load) * busiest->cpu_power, + *imbalance = min(max_pull * busiest->cpu_power, (avg_load - this_load) * this->cpu_power) / SCHED_LOAD_SCALE; -- GitLab From 12c62c2e9abf8da804fe1def1f5bb44d023f569f Mon Sep 17 00:00:00 2001 From: Arthur Othieno <a.othieno@bluewin.ch> Date: Sat, 10 Sep 2005 00:26:22 -0700 Subject: [PATCH 360/563] [PATCH] Remove even more stale references to Documentation/smp.tex Randy cleaned out the bulk of these stale references to the now long gone Documentation/smp.tex back in 2004. I followed this up with a few more sweeps. Somehow, these have managed to sneak back in since. I can't seem to figure out a contact point for M32R (no one listed in MAINTAINERS!), but, these patches are only but trivial. Signed-off-by: Arthur Othieno <a.othieno@bluewin.ch> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/arm/Kconfig | 4 ++-- arch/m32r/Kconfig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 0f2899b4159df..11fff042aa817 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -326,8 +326,8 @@ config SMP processor machines. On a single processor machine, the kernel will run faster if you say N here. - See also the <file:Documentation/smp.tex>, - <file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>, + See also the <file:Documentation/smp.txt>, + <file:Documentation/i386/IO-APIC.txt>, <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at <http://www.linuxdoc.org/docs.html#howto>. diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 7622d4ec5f08d..1ef3987ebc6ac 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -242,8 +242,8 @@ config SMP Y to "Enhanced Real Time Clock Support", below. The "Advanced Power Management" code will be disabled if you say Y here. - See also the <file:Documentation/smp.tex>, - <file:Documentation/smp.txt> and the SMP-HOWTO available at + See also the <file:Documentation/smp.txt>, + and the SMP-HOWTO available at <http://www.linuxdoc.org/docs.html#howto>. If you don't know what to do here, say N. -- GitLab From dd81eca83c8300c95d8a1eaf0d38f56513711535 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" <paulmck@us.ibm.com> Date: Sat, 10 Sep 2005 00:26:24 -0700 Subject: [PATCH 361/563] [PATCH] Yet another RCU documentation update Update RCU documentation based on discussions and review of RCU-based tree patches. Add an introductory whatisRCU.txt file. Signed-off-by: <paulmck@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/RCU/RTFP.txt | 36 +- Documentation/RCU/UP.txt | 79 ++- Documentation/RCU/checklist.txt | 23 +- Documentation/RCU/rcu.txt | 48 ++ Documentation/RCU/whatisRCU.txt | 902 ++++++++++++++++++++++++++++++++ 5 files changed, 1064 insertions(+), 24 deletions(-) create mode 100644 Documentation/RCU/whatisRCU.txt diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt index 9c6d450138ead..fcbcbc35b122f 100644 --- a/Documentation/RCU/RTFP.txt +++ b/Documentation/RCU/RTFP.txt @@ -2,7 +2,8 @@ Read the F-ing Papers! This document describes RCU-related publications, and is followed by -the corresponding bibtex entries. +the corresponding bibtex entries. A number of the publications may +be found at http://www.rdrop.com/users/paulmck/RCU/. The first thing resembling RCU was published in 1980, when Kung and Lehman [Kung80] recommended use of a garbage collector to defer destruction @@ -113,6 +114,10 @@ describing how to make RCU safe for soft-realtime applications [Sarma04c], and a paper describing SELinux performance with RCU [JamesMorris04b]. +2005 has seen further adaptation of RCU to realtime use, permitting +preemption of RCU realtime critical sections [PaulMcKenney05a, +PaulMcKenney05b]. + Bibtex Entries @article{Kung80 @@ -410,3 +415,32 @@ Oregon Health and Sciences University" \url{http://www.livejournal.com/users/james_morris/2153.html} [Viewed December 10, 2004]" } + +@unpublished{PaulMcKenney05a +,Author="Paul E. McKenney" +,Title="{[RFC]} {RCU} and {CONFIG\_PREEMPT\_RT} progress" +,month="May" +,year="2005" +,note="Available: +\url{http://lkml.org/lkml/2005/5/9/185} +[Viewed May 13, 2005]" +,annotation=" + First publication of working lock-based deferred free patches + for the CONFIG_PREEMPT_RT environment. +" +} + +@conference{PaulMcKenney05b +,Author="Paul E. McKenney and Dipankar Sarma" +,Title="Towards Hard Realtime Response from the Linux Kernel on SMP Hardware" +,Booktitle="linux.conf.au 2005" +,month="April" +,year="2005" +,address="Canberra, Australia" +,note="Available: +\url{http://www.rdrop.com/users/paulmck/RCU/realtimeRCU.2005.04.23a.pdf} +[Viewed May 13, 2005]" +,annotation=" + Realtime turns into making RCU yet more realtime friendly. +" +} diff --git a/Documentation/RCU/UP.txt b/Documentation/RCU/UP.txt index 3bfb84b3b7dbc..aab4a9ec39315 100644 --- a/Documentation/RCU/UP.txt +++ b/Documentation/RCU/UP.txt @@ -8,7 +8,7 @@ is that since there is only one CPU, it should not be necessary to wait for anything else to get done, since there are no other CPUs for anything else to be happening on. Although this approach will -sort- -of- work a surprising amount of the time, it is a very bad idea in general. -This document presents two examples that demonstrate exactly how bad an +This document presents three examples that demonstrate exactly how bad an idea this is. @@ -26,6 +26,9 @@ from softirq, the list scan would find itself referencing a newly freed element B. This situation can greatly decrease the life expectancy of your kernel. +This same problem can occur if call_rcu() is invoked from a hardware +interrupt handler. + Example 2: Function-Call Fatality @@ -44,8 +47,37 @@ its arguments would cause it to fail to make the fundamental guarantee underlying RCU, namely that call_rcu() defers invoking its arguments until all RCU read-side critical sections currently executing have completed. -Quick Quiz: why is it -not- legal to invoke synchronize_rcu() in -this case? +Quick Quiz #1: why is it -not- legal to invoke synchronize_rcu() in + this case? + + +Example 3: Death by Deadlock + +Suppose that call_rcu() is invoked while holding a lock, and that the +callback function must acquire this same lock. In this case, if +call_rcu() were to directly invoke the callback, the result would +be self-deadlock. + +In some cases, it would possible to restructure to code so that +the call_rcu() is delayed until after the lock is released. However, +there are cases where this can be quite ugly: + +1. If a number of items need to be passed to call_rcu() within + the same critical section, then the code would need to create + a list of them, then traverse the list once the lock was + released. + +2. In some cases, the lock will be held across some kernel API, + so that delaying the call_rcu() until the lock is released + requires that the data item be passed up via a common API. + It is far better to guarantee that callbacks are invoked + with no locks held than to have to modify such APIs to allow + arbitrary data items to be passed back up through them. + +If call_rcu() directly invokes the callback, painful locking restrictions +or API changes would be required. + +Quick Quiz #2: What locking restriction must RCU callbacks respect? Summary @@ -53,12 +85,35 @@ Summary Permitting call_rcu() to immediately invoke its arguments or permitting synchronize_rcu() to immediately return breaks RCU, even on a UP system. So do not do it! Even on a UP system, the RCU infrastructure -must- -respect grace periods. - - -Answer to Quick Quiz - -The calling function is scanning an RCU-protected linked list, and -is therefore within an RCU read-side critical section. Therefore, -the called function has been invoked within an RCU read-side critical -section, and is not permitted to block. +respect grace periods, and -must- invoke callbacks from a known environment +in which no locks are held. + + +Answer to Quick Quiz #1: + Why is it -not- legal to invoke synchronize_rcu() in this case? + + Because the calling function is scanning an RCU-protected linked + list, and is therefore within an RCU read-side critical section. + Therefore, the called function has been invoked within an RCU + read-side critical section, and is not permitted to block. + +Answer to Quick Quiz #2: + What locking restriction must RCU callbacks respect? + + Any lock that is acquired within an RCU callback must be + acquired elsewhere using an _irq variant of the spinlock + primitive. For example, if "mylock" is acquired by an + RCU callback, then a process-context acquisition of this + lock must use something like spin_lock_irqsave() to + acquire the lock. + + If the process-context code were to simply use spin_lock(), + then, since RCU callbacks can be invoked from softirq context, + the callback might be called from a softirq that interrupted + the process-context critical section. This would result in + self-deadlock. + + This restriction might seem gratuitous, since very few RCU + callbacks acquire locks directly. However, a great many RCU + callbacks do acquire locks -indirectly-, for example, via + the kfree() primitive. diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt index 8f3fb77c9cd32..e118a7c1a0928 100644 --- a/Documentation/RCU/checklist.txt +++ b/Documentation/RCU/checklist.txt @@ -43,6 +43,10 @@ over a rather long period of time, but improvements are always welcome! rcu_read_lock_bh()) in the read-side critical sections, and are also an excellent aid to readability. + As a rough rule of thumb, any dereference of an RCU-protected + pointer must be covered by rcu_read_lock() or rcu_read_lock_bh() + or by the appropriate update-side lock. + 3. Does the update code tolerate concurrent accesses? The whole point of RCU is to permit readers to run without @@ -90,7 +94,11 @@ over a rather long period of time, but improvements are always welcome! The rcu_dereference() primitive is used by the various "_rcu()" list-traversal primitives, such as the - list_for_each_entry_rcu(). + list_for_each_entry_rcu(). Note that it is perfectly + legal (if redundant) for update-side code to use + rcu_dereference() and the "_rcu()" list-traversal + primitives. This is particularly useful in code + that is common to readers and updaters. b. If the list macros are being used, the list_add_tail_rcu() and list_add_rcu() primitives must be used in order @@ -150,16 +158,9 @@ over a rather long period of time, but improvements are always welcome! Use of the _rcu() list-traversal primitives outside of an RCU read-side critical section causes no harm other than - a slight performance degradation on Alpha CPUs and some - confusion on the part of people trying to read the code. - - Another way of thinking of this is "If you are holding the - lock that prevents the data structure from changing, why do - you also need RCU-based protection?" That said, there may - well be situations where use of the _rcu() list-traversal - primitives while the update-side lock is held results in - simpler and more maintainable code. The jury is still out - on this question. + a slight performance degradation on Alpha CPUs. It can + also be quite helpful in reducing code bloat when common + code is shared between readers and updaters. 10. Conversely, if you are in an RCU read-side critical section, you -must- use the "_rcu()" variants of the list macros. diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt index eb444006683e2..6fa092251586e 100644 --- a/Documentation/RCU/rcu.txt +++ b/Documentation/RCU/rcu.txt @@ -64,6 +64,54 @@ o I hear that RCU is patented? What is with that? Of these, one was allowed to lapse by the assignee, and the others have been contributed to the Linux kernel under GPL. +o I hear that RCU needs work in order to support realtime kernels? + + Yes, work in progress. + o Where can I find more information on RCU? See the RTFP.txt file in this directory. + Or point your browser at http://www.rdrop.com/users/paulmck/RCU/. + +o What are all these files in this directory? + + + NMI-RCU.txt + + Describes how to use RCU to implement dynamic + NMI handlers, which can be revectored on the fly, + without rebooting. + + RTFP.txt + + List of RCU-related publications and web sites. + + UP.txt + + Discussion of RCU usage in UP kernels. + + arrayRCU.txt + + Describes how to use RCU to protect arrays, with + resizeable arrays whose elements reference other + data structures being of the most interest. + + checklist.txt + + Lists things to check for when inspecting code that + uses RCU. + + listRCU.txt + + Describes how to use RCU to protect linked lists. + This is the simplest and most common use of RCU + in the Linux kernel. + + rcu.txt + + You are reading it! + + whatisRCU.txt + + Overview of how the RCU implementation works. Along + the way, presents a conceptual view of RCU. diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt new file mode 100644 index 0000000000000..354d89c783777 --- /dev/null +++ b/Documentation/RCU/whatisRCU.txt @@ -0,0 +1,902 @@ +What is RCU? + +RCU is a synchronization mechanism that was added to the Linux kernel +during the 2.5 development effort that is optimized for read-mostly +situations. Although RCU is actually quite simple once you understand it, +getting there can sometimes be a challenge. Part of the problem is that +most of the past descriptions of RCU have been written with the mistaken +assumption that there is "one true way" to describe RCU. Instead, +the experience has been that different people must take different paths +to arrive at an understanding of RCU. This document provides several +different paths, as follows: + +1. RCU OVERVIEW +2. WHAT IS RCU'S CORE API? +3. WHAT ARE SOME EXAMPLE USES OF CORE RCU API? +4. WHAT IF MY UPDATING THREAD CANNOT BLOCK? +5. WHAT ARE SOME SIMPLE IMPLEMENTATIONS OF RCU? +6. ANALOGY WITH READER-WRITER LOCKING +7. FULL LIST OF RCU APIs +8. ANSWERS TO QUICK QUIZZES + +People who prefer starting with a conceptual overview should focus on +Section 1, though most readers will profit by reading this section at +some point. People who prefer to start with an API that they can then +experiment with should focus on Section 2. People who prefer to start +with example uses should focus on Sections 3 and 4. People who need to +understand the RCU implementation should focus on Section 5, then dive +into the kernel source code. People who reason best by analogy should +focus on Section 6. Section 7 serves as an index to the docbook API +documentation, and Section 8 is the traditional answer key. + +So, start with the section that makes the most sense to you and your +preferred method of learning. If you need to know everything about +everything, feel free to read the whole thing -- but if you are really +that type of person, you have perused the source code and will therefore +never need this document anyway. ;-) + + +1. RCU OVERVIEW + +The basic idea behind RCU is to split updates into "removal" and +"reclamation" phases. The removal phase removes references to data items +within a data structure (possibly by replacing them with references to +new versions of these data items), and can run concurrently with readers. +The reason that it is safe to run the removal phase concurrently with +readers is the semantics of modern CPUs guarantee that readers will see +either the old or the new version of the data structure rather than a +partially updated reference. The reclamation phase does the work of reclaiming +(e.g., freeing) the data items removed from the data structure during the +removal phase. Because reclaiming data items can disrupt any readers +concurrently referencing those data items, the reclamation phase must +not start until readers no longer hold references to those data items. + +Splitting the update into removal and reclamation phases permits the +updater to perform the removal phase immediately, and to defer the +reclamation phase until all readers active during the removal phase have +completed, either by blocking until they finish or by registering a +callback that is invoked after they finish. Only readers that are active +during the removal phase need be considered, because any reader starting +after the removal phase will be unable to gain a reference to the removed +data items, and therefore cannot be disrupted by the reclamation phase. + +So the typical RCU update sequence goes something like the following: + +a. Remove pointers to a data structure, so that subsequent + readers cannot gain a reference to it. + +b. Wait for all previous readers to complete their RCU read-side + critical sections. + +c. At this point, there cannot be any readers who hold references + to the data structure, so it now may safely be reclaimed + (e.g., kfree()d). + +Step (b) above is the key idea underlying RCU's deferred destruction. +The ability to wait until all readers are done allows RCU readers to +use much lighter-weight synchronization, in some cases, absolutely no +synchronization at all. In contrast, in more conventional lock-based +schemes, readers must use heavy-weight synchronization in order to +prevent an updater from deleting the data structure out from under them. +This is because lock-based updaters typically update data items in place, +and must therefore exclude readers. In contrast, RCU-based updaters +typically take advantage of the fact that writes to single aligned +pointers are atomic on modern CPUs, allowing atomic insertion, removal, +and replacement of data items in a linked structure without disrupting +readers. Concurrent RCU readers can then continue accessing the old +versions, and can dispense with the atomic operations, memory barriers, +and communications cache misses that are so expensive on present-day +SMP computer systems, even in absence of lock contention. + +In the three-step procedure shown above, the updater is performing both +the removal and the reclamation step, but it is often helpful for an +entirely different thread to do the reclamation, as is in fact the case +in the Linux kernel's directory-entry cache (dcache). Even if the same +thread performs both the update step (step (a) above) and the reclamation +step (step (c) above), it is often helpful to think of them separately. +For example, RCU readers and updaters need not communicate at all, +but RCU provides implicit low-overhead communication between readers +and reclaimers, namely, in step (b) above. + +So how the heck can a reclaimer tell when a reader is done, given +that readers are not doing any sort of synchronization operations??? +Read on to learn about how RCU's API makes this easy. + + +2. WHAT IS RCU'S CORE API? + +The core RCU API is quite small: + +a. rcu_read_lock() +b. rcu_read_unlock() +c. synchronize_rcu() / call_rcu() +d. rcu_assign_pointer() +e. rcu_dereference() + +There are many other members of the RCU API, but the rest can be +expressed in terms of these five, though most implementations instead +express synchronize_rcu() in terms of the call_rcu() callback API. + +The five core RCU APIs are described below, the other 18 will be enumerated +later. See the kernel docbook documentation for more info, or look directly +at the function header comments. + +rcu_read_lock() + + void rcu_read_lock(void); + + Used by a reader to inform the reclaimer that the reader is + entering an RCU read-side critical section. It is illegal + to block while in an RCU read-side critical section, though + kernels built with CONFIG_PREEMPT_RCU can preempt RCU read-side + critical sections. Any RCU-protected data structure accessed + during an RCU read-side critical section is guaranteed to remain + unreclaimed for the full duration of that critical section. + Reference counts may be used in conjunction with RCU to maintain + longer-term references to data structures. + +rcu_read_unlock() + + void rcu_read_unlock(void); + + Used by a reader to inform the reclaimer that the reader is + exiting an RCU read-side critical section. Note that RCU + read-side critical sections may be nested and/or overlapping. + +synchronize_rcu() + + void synchronize_rcu(void); + + Marks the end of updater code and the beginning of reclaimer + code. It does this by blocking until all pre-existing RCU + read-side critical sections on all CPUs have completed. + Note that synchronize_rcu() will -not- necessarily wait for + any subsequent RCU read-side critical sections to complete. + For example, consider the following sequence of events: + + CPU 0 CPU 1 CPU 2 + ----------------- ------------------------- --------------- + 1. rcu_read_lock() + 2. enters synchronize_rcu() + 3. rcu_read_lock() + 4. rcu_read_unlock() + 5. exits synchronize_rcu() + 6. rcu_read_unlock() + + To reiterate, synchronize_rcu() waits only for ongoing RCU + read-side critical sections to complete, not necessarily for + any that begin after synchronize_rcu() is invoked. + + Of course, synchronize_rcu() does not necessarily return + -immediately- after the last pre-existing RCU read-side critical + section completes. For one thing, there might well be scheduling + delays. For another thing, many RCU implementations process + requests in batches in order to improve efficiencies, which can + further delay synchronize_rcu(). + + Since synchronize_rcu() is the API that must figure out when + readers are done, its implementation is key to RCU. For RCU + to be useful in all but the most read-intensive situations, + synchronize_rcu()'s overhead must also be quite small. + + The call_rcu() API is a callback form of synchronize_rcu(), + and is described in more detail in a later section. Instead of + blocking, it registers a function and argument which are invoked + after all ongoing RCU read-side critical sections have completed. + This callback variant is particularly useful in situations where + it is illegal to block. + +rcu_assign_pointer() + + typeof(p) rcu_assign_pointer(p, typeof(p) v); + + Yes, rcu_assign_pointer() -is- implemented as a macro, though it + would be cool to be able to declare a function in this manner. + (Compiler experts will no doubt disagree.) + + The updater uses this function to assign a new value to an + RCU-protected pointer, in order to safely communicate the change + in value from the updater to the reader. This function returns + the new value, and also executes any memory-barrier instructions + required for a given CPU architecture. + + Perhaps more important, it serves to document which pointers + are protected by RCU. That said, rcu_assign_pointer() is most + frequently used indirectly, via the _rcu list-manipulation + primitives such as list_add_rcu(). + +rcu_dereference() + + typeof(p) rcu_dereference(p); + + Like rcu_assign_pointer(), rcu_dereference() must be implemented + as a macro. + + The reader uses rcu_dereference() to fetch an RCU-protected + pointer, which returns a value that may then be safely + dereferenced. Note that rcu_deference() does not actually + dereference the pointer, instead, it protects the pointer for + later dereferencing. It also executes any needed memory-barrier + instructions for a given CPU architecture. Currently, only Alpha + needs memory barriers within rcu_dereference() -- on other CPUs, + it compiles to nothing, not even a compiler directive. + + Common coding practice uses rcu_dereference() to copy an + RCU-protected pointer to a local variable, then dereferences + this local variable, for example as follows: + + p = rcu_dereference(head.next); + return p->data; + + However, in this case, one could just as easily combine these + into one statement: + + return rcu_dereference(head.next)->data; + + If you are going to be fetching multiple fields from the + RCU-protected structure, using the local variable is of + course preferred. Repeated rcu_dereference() calls look + ugly and incur unnecessary overhead on Alpha CPUs. + + Note that the value returned by rcu_dereference() is valid + only within the enclosing RCU read-side critical section. + For example, the following is -not- legal: + + rcu_read_lock(); + p = rcu_dereference(head.next); + rcu_read_unlock(); + x = p->address; + rcu_read_lock(); + y = p->data; + rcu_read_unlock(); + + Holding a reference from one RCU read-side critical section + to another is just as illegal as holding a reference from + one lock-based critical section to another! Similarly, + using a reference outside of the critical section in which + it was acquired is just as illegal as doing so with normal + locking. + + As with rcu_assign_pointer(), an important function of + rcu_dereference() is to document which pointers are protected + by RCU. And, again like rcu_assign_pointer(), rcu_dereference() + is typically used indirectly, via the _rcu list-manipulation + primitives, such as list_for_each_entry_rcu(). + +The following diagram shows how each API communicates among the +reader, updater, and reclaimer. + + + rcu_assign_pointer() + +--------+ + +---------------------->| reader |---------+ + | +--------+ | + | | | + | | | Protect: + | | | rcu_read_lock() + | | | rcu_read_unlock() + | rcu_dereference() | | + +---------+ | | + | updater |<---------------------+ | + +---------+ V + | +-----------+ + +----------------------------------->| reclaimer | + +-----------+ + Defer: + synchronize_rcu() & call_rcu() + + +The RCU infrastructure observes the time sequence of rcu_read_lock(), +rcu_read_unlock(), synchronize_rcu(), and call_rcu() invocations in +order to determine when (1) synchronize_rcu() invocations may return +to their callers and (2) call_rcu() callbacks may be invoked. Efficient +implementations of the RCU infrastructure make heavy use of batching in +order to amortize their overhead over many uses of the corresponding APIs. + +There are no fewer than three RCU mechanisms in the Linux kernel; the +diagram above shows the first one, which is by far the most commonly used. +The rcu_dereference() and rcu_assign_pointer() primitives are used for +all three mechanisms, but different defer and protect primitives are +used as follows: + + Defer Protect + +a. synchronize_rcu() rcu_read_lock() / rcu_read_unlock() + call_rcu() + +b. call_rcu_bh() rcu_read_lock_bh() / rcu_read_unlock_bh() + +c. synchronize_sched() preempt_disable() / preempt_enable() + local_irq_save() / local_irq_restore() + hardirq enter / hardirq exit + NMI enter / NMI exit + +These three mechanisms are used as follows: + +a. RCU applied to normal data structures. + +b. RCU applied to networking data structures that may be subjected + to remote denial-of-service attacks. + +c. RCU applied to scheduler and interrupt/NMI-handler tasks. + +Again, most uses will be of (a). The (b) and (c) cases are important +for specialized uses, but are relatively uncommon. + + +3. WHAT ARE SOME EXAMPLE USES OF CORE RCU API? + +This section shows a simple use of the core RCU API to protect a +global pointer to a dynamically allocated structure. More typical +uses of RCU may be found in listRCU.txt, arrayRCU.txt, and NMI-RCU.txt. + + struct foo { + int a; + char b; + long c; + }; + DEFINE_SPINLOCK(foo_mutex); + + struct foo *gbl_foo; + + /* + * Create a new struct foo that is the same as the one currently + * pointed to by gbl_foo, except that field "a" is replaced + * with "new_a". Points gbl_foo to the new structure, and + * frees up the old structure after a grace period. + * + * Uses rcu_assign_pointer() to ensure that concurrent readers + * see the initialized version of the new structure. + * + * Uses synchronize_rcu() to ensure that any readers that might + * have references to the old structure complete before freeing + * the old structure. + */ + void foo_update_a(int new_a) + { + struct foo *new_fp; + struct foo *old_fp; + + new_fp = kmalloc(sizeof(*fp), GFP_KERNEL); + spin_lock(&foo_mutex); + old_fp = gbl_foo; + *new_fp = *old_fp; + new_fp->a = new_a; + rcu_assign_pointer(gbl_foo, new_fp); + spin_unlock(&foo_mutex); + synchronize_rcu(); + kfree(old_fp); + } + + /* + * Return the value of field "a" of the current gbl_foo + * structure. Use rcu_read_lock() and rcu_read_unlock() + * to ensure that the structure does not get deleted out + * from under us, and use rcu_dereference() to ensure that + * we see the initialized version of the structure (important + * for DEC Alpha and for people reading the code). + */ + int foo_get_a(void) + { + int retval; + + rcu_read_lock(); + retval = rcu_dereference(gbl_foo)->a; + rcu_read_unlock(); + return retval; + } + +So, to sum up: + +o Use rcu_read_lock() and rcu_read_unlock() to guard RCU + read-side critical sections. + +o Within an RCU read-side critical section, use rcu_dereference() + to dereference RCU-protected pointers. + +o Use some solid scheme (such as locks or semaphores) to + keep concurrent updates from interfering with each other. + +o Use rcu_assign_pointer() to update an RCU-protected pointer. + This primitive protects concurrent readers from the updater, + -not- concurrent updates from each other! You therefore still + need to use locking (or something similar) to keep concurrent + rcu_assign_pointer() primitives from interfering with each other. + +o Use synchronize_rcu() -after- removing a data element from an + RCU-protected data structure, but -before- reclaiming/freeing + the data element, in order to wait for the completion of all + RCU read-side critical sections that might be referencing that + data item. + +See checklist.txt for additional rules to follow when using RCU. + + +4. WHAT IF MY UPDATING THREAD CANNOT BLOCK? + +In the example above, foo_update_a() blocks until a grace period elapses. +This is quite simple, but in some cases one cannot afford to wait so +long -- there might be other high-priority work to be done. + +In such cases, one uses call_rcu() rather than synchronize_rcu(). +The call_rcu() API is as follows: + + void call_rcu(struct rcu_head * head, + void (*func)(struct rcu_head *head)); + +This function invokes func(head) after a grace period has elapsed. +This invocation might happen from either softirq or process context, +so the function is not permitted to block. The foo struct needs to +have an rcu_head structure added, perhaps as follows: + + struct foo { + int a; + char b; + long c; + struct rcu_head rcu; + }; + +The foo_update_a() function might then be written as follows: + + /* + * Create a new struct foo that is the same as the one currently + * pointed to by gbl_foo, except that field "a" is replaced + * with "new_a". Points gbl_foo to the new structure, and + * frees up the old structure after a grace period. + * + * Uses rcu_assign_pointer() to ensure that concurrent readers + * see the initialized version of the new structure. + * + * Uses call_rcu() to ensure that any readers that might have + * references to the old structure complete before freeing the + * old structure. + */ + void foo_update_a(int new_a) + { + struct foo *new_fp; + struct foo *old_fp; + + new_fp = kmalloc(sizeof(*fp), GFP_KERNEL); + spin_lock(&foo_mutex); + old_fp = gbl_foo; + *new_fp = *old_fp; + new_fp->a = new_a; + rcu_assign_pointer(gbl_foo, new_fp); + spin_unlock(&foo_mutex); + call_rcu(&old_fp->rcu, foo_reclaim); + } + +The foo_reclaim() function might appear as follows: + + void foo_reclaim(struct rcu_head *rp) + { + struct foo *fp = container_of(rp, struct foo, rcu); + + kfree(fp); + } + +The container_of() primitive is a macro that, given a pointer into a +struct, the type of the struct, and the pointed-to field within the +struct, returns a pointer to the beginning of the struct. + +The use of call_rcu() permits the caller of foo_update_a() to +immediately regain control, without needing to worry further about the +old version of the newly updated element. It also clearly shows the +RCU distinction between updater, namely foo_update_a(), and reclaimer, +namely foo_reclaim(). + +The summary of advice is the same as for the previous section, except +that we are now using call_rcu() rather than synchronize_rcu(): + +o Use call_rcu() -after- removing a data element from an + RCU-protected data structure in order to register a callback + function that will be invoked after the completion of all RCU + read-side critical sections that might be referencing that + data item. + +Again, see checklist.txt for additional rules governing the use of RCU. + + +5. WHAT ARE SOME SIMPLE IMPLEMENTATIONS OF RCU? + +One of the nice things about RCU is that it has extremely simple "toy" +implementations that are a good first step towards understanding the +production-quality implementations in the Linux kernel. This section +presents two such "toy" implementations of RCU, one that is implemented +in terms of familiar locking primitives, and another that more closely +resembles "classic" RCU. Both are way too simple for real-world use, +lacking both functionality and performance. However, they are useful +in getting a feel for how RCU works. See kernel/rcupdate.c for a +production-quality implementation, and see: + + http://www.rdrop.com/users/paulmck/RCU + +for papers describing the Linux kernel RCU implementation. The OLS'01 +and OLS'02 papers are a good introduction, and the dissertation provides +more details on the current implementation. + + +5A. "TOY" IMPLEMENTATION #1: LOCKING + +This section presents a "toy" RCU implementation that is based on +familiar locking primitives. Its overhead makes it a non-starter for +real-life use, as does its lack of scalability. It is also unsuitable +for realtime use, since it allows scheduling latency to "bleed" from +one read-side critical section to another. + +However, it is probably the easiest implementation to relate to, so is +a good starting point. + +It is extremely simple: + + static DEFINE_RWLOCK(rcu_gp_mutex); + + void rcu_read_lock(void) + { + read_lock(&rcu_gp_mutex); + } + + void rcu_read_unlock(void) + { + read_unlock(&rcu_gp_mutex); + } + + void synchronize_rcu(void) + { + write_lock(&rcu_gp_mutex); + write_unlock(&rcu_gp_mutex); + } + +[You can ignore rcu_assign_pointer() and rcu_dereference() without +missing much. But here they are anyway. And whatever you do, don't +forget about them when submitting patches making use of RCU!] + + #define rcu_assign_pointer(p, v) ({ \ + smp_wmb(); \ + (p) = (v); \ + }) + + #define rcu_dereference(p) ({ \ + typeof(p) _________p1 = p; \ + smp_read_barrier_depends(); \ + (_________p1); \ + }) + + +The rcu_read_lock() and rcu_read_unlock() primitive read-acquire +and release a global reader-writer lock. The synchronize_rcu() +primitive write-acquires this same lock, then immediately releases +it. This means that once synchronize_rcu() exits, all RCU read-side +critical sections that were in progress before synchonize_rcu() was +called are guaranteed to have completed -- there is no way that +synchronize_rcu() would have been able to write-acquire the lock +otherwise. + +It is possible to nest rcu_read_lock(), since reader-writer locks may +be recursively acquired. Note also that rcu_read_lock() is immune +from deadlock (an important property of RCU). The reason for this is +that the only thing that can block rcu_read_lock() is a synchronize_rcu(). +But synchronize_rcu() does not acquire any locks while holding rcu_gp_mutex, +so there can be no deadlock cycle. + +Quick Quiz #1: Why is this argument naive? How could a deadlock + occur when using this algorithm in a real-world Linux + kernel? How could this deadlock be avoided? + + +5B. "TOY" EXAMPLE #2: CLASSIC RCU + +This section presents a "toy" RCU implementation that is based on +"classic RCU". It is also short on performance (but only for updates) and +on features such as hotplug CPU and the ability to run in CONFIG_PREEMPT +kernels. The definitions of rcu_dereference() and rcu_assign_pointer() +are the same as those shown in the preceding section, so they are omitted. + + void rcu_read_lock(void) { } + + void rcu_read_unlock(void) { } + + void synchronize_rcu(void) + { + int cpu; + + for_each_cpu(cpu) + run_on(cpu); + } + +Note that rcu_read_lock() and rcu_read_unlock() do absolutely nothing. +This is the great strength of classic RCU in a non-preemptive kernel: +read-side overhead is precisely zero, at least on non-Alpha CPUs. +And there is absolutely no way that rcu_read_lock() can possibly +participate in a deadlock cycle! + +The implementation of synchronize_rcu() simply schedules itself on each +CPU in turn. The run_on() primitive can be implemented straightforwardly +in terms of the sched_setaffinity() primitive. Of course, a somewhat less +"toy" implementation would restore the affinity upon completion rather +than just leaving all tasks running on the last CPU, but when I said +"toy", I meant -toy-! + +So how the heck is this supposed to work??? + +Remember that it is illegal to block while in an RCU read-side critical +section. Therefore, if a given CPU executes a context switch, we know +that it must have completed all preceding RCU read-side critical sections. +Once -all- CPUs have executed a context switch, then -all- preceding +RCU read-side critical sections will have completed. + +So, suppose that we remove a data item from its structure and then invoke +synchronize_rcu(). Once synchronize_rcu() returns, we are guaranteed +that there are no RCU read-side critical sections holding a reference +to that data item, so we can safely reclaim it. + +Quick Quiz #2: Give an example where Classic RCU's read-side + overhead is -negative-. + +Quick Quiz #3: If it is illegal to block in an RCU read-side + critical section, what the heck do you do in + PREEMPT_RT, where normal spinlocks can block??? + + +6. ANALOGY WITH READER-WRITER LOCKING + +Although RCU can be used in many different ways, a very common use of +RCU is analogous to reader-writer locking. The following unified +diff shows how closely related RCU and reader-writer locking can be. + + @@ -13,15 +14,15 @@ + struct list_head *lp; + struct el *p; + + - read_lock(); + - list_for_each_entry(p, head, lp) { + + rcu_read_lock(); + + list_for_each_entry_rcu(p, head, lp) { + if (p->key == key) { + *result = p->data; + - read_unlock(); + + rcu_read_unlock(); + return 1; + } + } + - read_unlock(); + + rcu_read_unlock(); + return 0; + } + + @@ -29,15 +30,16 @@ + { + struct el *p; + + - write_lock(&listmutex); + + spin_lock(&listmutex); + list_for_each_entry(p, head, lp) { + if (p->key == key) { + list_del(&p->list); + - write_unlock(&listmutex); + + spin_unlock(&listmutex); + + synchronize_rcu(); + kfree(p); + return 1; + } + } + - write_unlock(&listmutex); + + spin_unlock(&listmutex); + return 0; + } + +Or, for those who prefer a side-by-side listing: + + 1 struct el { 1 struct el { + 2 struct list_head list; 2 struct list_head list; + 3 long key; 3 long key; + 4 spinlock_t mutex; 4 spinlock_t mutex; + 5 int data; 5 int data; + 6 /* Other data fields */ 6 /* Other data fields */ + 7 }; 7 }; + 8 spinlock_t listmutex; 8 spinlock_t listmutex; + 9 struct el head; 9 struct el head; + + 1 int search(long key, int *result) 1 int search(long key, int *result) + 2 { 2 { + 3 struct list_head *lp; 3 struct list_head *lp; + 4 struct el *p; 4 struct el *p; + 5 5 + 6 read_lock(); 6 rcu_read_lock(); + 7 list_for_each_entry(p, head, lp) { 7 list_for_each_entry_rcu(p, head, lp) { + 8 if (p->key == key) { 8 if (p->key == key) { + 9 *result = p->data; 9 *result = p->data; +10 read_unlock(); 10 rcu_read_unlock(); +11 return 1; 11 return 1; +12 } 12 } +13 } 13 } +14 read_unlock(); 14 rcu_read_unlock(); +15 return 0; 15 return 0; +16 } 16 } + + 1 int delete(long key) 1 int delete(long key) + 2 { 2 { + 3 struct el *p; 3 struct el *p; + 4 4 + 5 write_lock(&listmutex); 5 spin_lock(&listmutex); + 6 list_for_each_entry(p, head, lp) { 6 list_for_each_entry(p, head, lp) { + 7 if (p->key == key) { 7 if (p->key == key) { + 8 list_del(&p->list); 8 list_del(&p->list); + 9 write_unlock(&listmutex); 9 spin_unlock(&listmutex); + 10 synchronize_rcu(); +10 kfree(p); 11 kfree(p); +11 return 1; 12 return 1; +12 } 13 } +13 } 14 } +14 write_unlock(&listmutex); 15 spin_unlock(&listmutex); +15 return 0; 16 return 0; +16 } 17 } + +Either way, the differences are quite small. Read-side locking moves +to rcu_read_lock() and rcu_read_unlock, update-side locking moves from +from a reader-writer lock to a simple spinlock, and a synchronize_rcu() +precedes the kfree(). + +However, there is one potential catch: the read-side and update-side +critical sections can now run concurrently. In many cases, this will +not be a problem, but it is necessary to check carefully regardless. +For example, if multiple independent list updates must be seen as +a single atomic update, converting to RCU will require special care. + +Also, the presence of synchronize_rcu() means that the RCU version of +delete() can now block. If this is a problem, there is a callback-based +mechanism that never blocks, namely call_rcu(), that can be used in +place of synchronize_rcu(). + + +7. FULL LIST OF RCU APIs + +The RCU APIs are documented in docbook-format header comments in the +Linux-kernel source code, but it helps to have a full list of the +APIs, since there does not appear to be a way to categorize them +in docbook. Here is the list, by category. + +Markers for RCU read-side critical sections: + + rcu_read_lock + rcu_read_unlock + rcu_read_lock_bh + rcu_read_unlock_bh + +RCU pointer/list traversal: + + rcu_dereference + list_for_each_rcu (to be deprecated in favor of + list_for_each_entry_rcu) + list_for_each_safe_rcu (deprecated, not used) + list_for_each_entry_rcu + list_for_each_continue_rcu (to be deprecated in favor of new + list_for_each_entry_continue_rcu) + hlist_for_each_rcu (to be deprecated in favor of + hlist_for_each_entry_rcu) + hlist_for_each_entry_rcu + +RCU pointer update: + + rcu_assign_pointer + list_add_rcu + list_add_tail_rcu + list_del_rcu + list_replace_rcu + hlist_del_rcu + hlist_add_head_rcu + +RCU grace period: + + synchronize_kernel (deprecated) + synchronize_net + synchronize_sched + synchronize_rcu + call_rcu + call_rcu_bh + +See the comment headers in the source code (or the docbook generated +from them) for more information. + + +8. ANSWERS TO QUICK QUIZZES + +Quick Quiz #1: Why is this argument naive? How could a deadlock + occur when using this algorithm in a real-world Linux + kernel? [Referring to the lock-based "toy" RCU + algorithm.] + +Answer: Consider the following sequence of events: + + 1. CPU 0 acquires some unrelated lock, call it + "problematic_lock". + + 2. CPU 1 enters synchronize_rcu(), write-acquiring + rcu_gp_mutex. + + 3. CPU 0 enters rcu_read_lock(), but must wait + because CPU 1 holds rcu_gp_mutex. + + 4. CPU 1 is interrupted, and the irq handler + attempts to acquire problematic_lock. + + The system is now deadlocked. + + One way to avoid this deadlock is to use an approach like + that of CONFIG_PREEMPT_RT, where all normal spinlocks + become blocking locks, and all irq handlers execute in + the context of special tasks. In this case, in step 4 + above, the irq handler would block, allowing CPU 1 to + release rcu_gp_mutex, avoiding the deadlock. + + Even in the absence of deadlock, this RCU implementation + allows latency to "bleed" from readers to other + readers through synchronize_rcu(). To see this, + consider task A in an RCU read-side critical section + (thus read-holding rcu_gp_mutex), task B blocked + attempting to write-acquire rcu_gp_mutex, and + task C blocked in rcu_read_lock() attempting to + read_acquire rcu_gp_mutex. Task A's RCU read-side + latency is holding up task C, albeit indirectly via + task B. + + Realtime RCU implementations therefore use a counter-based + approach where tasks in RCU read-side critical sections + cannot be blocked by tasks executing synchronize_rcu(). + +Quick Quiz #2: Give an example where Classic RCU's read-side + overhead is -negative-. + +Answer: Imagine a single-CPU system with a non-CONFIG_PREEMPT + kernel where a routing table is used by process-context + code, but can be updated by irq-context code (for example, + by an "ICMP REDIRECT" packet). The usual way of handling + this would be to have the process-context code disable + interrupts while searching the routing table. Use of + RCU allows such interrupt-disabling to be dispensed with. + Thus, without RCU, you pay the cost of disabling interrupts, + and with RCU you don't. + + One can argue that the overhead of RCU in this + case is negative with respect to the single-CPU + interrupt-disabling approach. Others might argue that + the overhead of RCU is merely zero, and that replacing + the positive overhead of the interrupt-disabling scheme + with the zero-overhead RCU scheme does not constitute + negative overhead. + + In real life, of course, things are more complex. But + even the theoretical possibility of negative overhead for + a synchronization primitive is a bit unexpected. ;-) + +Quick Quiz #3: If it is illegal to block in an RCU read-side + critical section, what the heck do you do in + PREEMPT_RT, where normal spinlocks can block??? + +Answer: Just as PREEMPT_RT permits preemption of spinlock + critical sections, it permits preemption of RCU + read-side critical sections. It also permits + spinlocks blocking while in RCU read-side critical + sections. + + Why the apparent inconsistency? Because it is it + possible to use priority boosting to keep the RCU + grace periods short if need be (for example, if running + short of memory). In contrast, if blocking waiting + for (say) network reception, there is no way to know + what should be boosted. Especially given that the + process we need to boost might well be a human being + who just went out for a pizza or something. And although + a computer-operated cattle prod might arouse serious + interest, it might also provoke serious objections. + Besides, how does the computer know what pizza parlor + the human being went to??? + + +ACKNOWLEDGEMENTS + +My thanks to the people who helped make this human-readable, including +Jon Walpole, Josh Triplett, Serge Hallyn, and Suzanne Wood. + + +For more information, see http://www.rdrop.com/users/paulmck/RCU. -- GitLab From 5ce7852cdf07ab903fb1c72d0915ac492c6e07c7 Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:26:28 -0700 Subject: [PATCH 362/563] [PATCH] mm/filemap.c: make two functions static With Nick Piggin <npiggin@suse.de> Give some things static scope. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/fs.h | 2 -- include/linux/writeback.h | 2 -- mm/filemap.c | 17 ++++++++++------- mm/memory.c | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 7f61227827d76..e0b77c5af9a02 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1509,8 +1509,6 @@ extern void do_generic_mapping_read(struct address_space *mapping, loff_t *, read_descriptor_t *, read_actor_t); extern void file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); -extern ssize_t generic_file_direct_IO(int rw, struct kiocb *iocb, - const struct iovec *iov, loff_t offset, unsigned long nr_segs); extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos); ssize_t generic_file_writev(struct file *filp, const struct iovec *iov, diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 542dbaee65129..343d883d69c5d 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -109,8 +109,6 @@ int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0); int do_writepages(struct address_space *mapping, struct writeback_control *wbc); int sync_page_range(struct inode *inode, struct address_space *mapping, loff_t pos, size_t count); -int sync_page_range_nolock(struct inode *inode, struct address_space - *mapping, loff_t pos, size_t count); /* pdflush.c */ extern int nr_pdflush_threads; /* Global so it can be exported to sysctl diff --git a/mm/filemap.c b/mm/filemap.c index 88611928e71fc..b5346576e58d2 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -37,6 +37,10 @@ #include <asm/uaccess.h> #include <asm/mman.h> +static ssize_t +generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, + loff_t offset, unsigned long nr_segs); + /* * Shared mappings implemented 30.11.1994. It's not fully working yet, * though. @@ -301,8 +305,9 @@ EXPORT_SYMBOL(sync_page_range); * as it forces O_SYNC writers to different parts of the same file * to be serialised right until io completion. */ -int sync_page_range_nolock(struct inode *inode, struct address_space *mapping, - loff_t pos, size_t count) +static int sync_page_range_nolock(struct inode *inode, + struct address_space *mapping, + loff_t pos, size_t count) { pgoff_t start = pos >> PAGE_CACHE_SHIFT; pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT; @@ -317,7 +322,6 @@ int sync_page_range_nolock(struct inode *inode, struct address_space *mapping, ret = wait_on_page_writeback_range(mapping, start, end); return ret; } -EXPORT_SYMBOL(sync_page_range_nolock); /** * filemap_fdatawait - walk the list of under-writeback pages of the given @@ -2008,7 +2012,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, } EXPORT_SYMBOL(generic_file_buffered_write); -ssize_t +static ssize_t __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) { @@ -2108,7 +2112,7 @@ generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, return ret; } -ssize_t +static ssize_t __generic_file_write_nolock(struct file *file, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) { @@ -2229,7 +2233,7 @@ EXPORT_SYMBOL(generic_file_writev); * Called under i_sem for writes to S_ISREG files. Returns -EIO if something * went wrong during pagecache shootdown. */ -ssize_t +static ssize_t generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) { @@ -2264,4 +2268,3 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, } return retval; } -EXPORT_SYMBOL_GPL(generic_file_direct_IO); diff --git a/mm/memory.c b/mm/memory.c index 788a628103405..ae8161f1f4595 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2225,7 +2225,7 @@ void update_mem_hiwater(struct task_struct *tsk) #if !defined(__HAVE_ARCH_GATE_AREA) #if defined(AT_SYSINFO_EHDR) -struct vm_area_struct gate_vma; +static struct vm_area_struct gate_vma; static int __init gate_vma_init(void) { -- GitLab From 819a3eba4233ffc6c125e1bf0a15ae093b97c3a6 Mon Sep 17 00:00:00 2001 From: Christophe Lucas <clucas@rotomalug.org> Date: Sat, 10 Sep 2005 00:26:29 -0700 Subject: [PATCH 363/563] [PATCH] applicom: fix error handling misc_register() can fail. Signed-off-by: Christophe Lucas <clucas@rotomalug.org> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/applicom.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 11f9ee5811242..927a5bbe112c9 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -172,7 +172,7 @@ static int ac_register_board(unsigned long physloc, void __iomem *loc, void cleanup_module(void) { - int i; + unsigned int i; misc_deregister(&ac_miscdev); @@ -195,7 +195,7 @@ int __init applicom_init(void) int i, numisa = 0; struct pci_dev *dev = NULL; void __iomem *RamIO; - int boardno; + int boardno, ret; printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $\n"); @@ -294,7 +294,8 @@ int __init applicom_init(void) } if (!numisa) - printk(KERN_WARNING"ac.o: No valid ISA Applicom boards found at mem 0x%lx\n",mem); + printk(KERN_WARNING "ac.o: No valid ISA Applicom boards found " + "at mem 0x%lx\n", mem); fin: init_waitqueue_head(&FlagSleepRec); @@ -304,7 +305,11 @@ int __init applicom_init(void) DeviceErrorCount = 0; if (numboards) { - misc_register(&ac_miscdev); + ret = misc_register(&ac_miscdev); + if (ret) { + printk(KERN_WARNING "ac.o: Unable to register misc device\n"); + goto out; + } for (i = 0; i < MAX_BOARD; i++) { int serial; char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1]; @@ -337,6 +342,17 @@ int __init applicom_init(void) else return -ENXIO; + +out: + for (i = 0; i < MAX_BOARD; i++) { + if (!apbs[i].RamIO) + continue; + if (apbs[i].irq) + free_irq(apbs[i].irq, &dummy); + iounmap(apbs[i].RamIO); + } + pci_disable_device(dev); + return ret; } -- GitLab From cf85d5ca880c9611906e0ca0c729fdf01c724501 Mon Sep 17 00:00:00 2001 From: Christophe Lucas <clucas@rotomalug.org> Date: Sat, 10 Sep 2005 00:26:32 -0700 Subject: [PATCH 364/563] [PATCH] drivers/char/lcd.c: misc_register() can fail Signed-off-by: Christophe Lucas <clucas@rotomalug.org> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/lcd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c index cf01a720eb2ef..b771611461445 100644 --- a/drivers/char/lcd.c +++ b/drivers/char/lcd.c @@ -613,10 +613,15 @@ static struct miscdevice lcd_dev = { static int lcd_init(void) { + int ret; unsigned long data; pr_info("%s\n", LCD_DRIVER); - misc_register(&lcd_dev); + ret = misc_register(&lcd_dev); + if (ret) { + printk(KERN_WARNING LCD "Unable to register misc device.\n"); + return ret; + } /* Check region? Naaah! Just snarf it up. */ /* request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/ -- GitLab From 1ac19f4ccd8636dbe76a97cec36c95d7548cc871 Mon Sep 17 00:00:00 2001 From: Christophe Lucas <clucas@rotomalug.org> Date: Sat, 10 Sep 2005 00:26:33 -0700 Subject: [PATCH 365/563] [PATCH] hdpu_cpustate.c: misc_register() can fail Signed-off-by: Christophe Lucas <clucas@rotomalug.org> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/misc/hdpuftrs/hdpu_cpustate.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 7501fab349e4c..46de5c9405557 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -192,22 +192,37 @@ static int hdpu_cpustate_probe(struct device *ddev) { struct platform_device *pdev = to_platform_device(ddev); struct resource *res; + struct proc_dir_entry *proc_de; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); cpustate.set_addr = (unsigned long *)res->start; cpustate.clr_addr = (unsigned long *)res->end - 1; - misc_register(&cpustate_dev); - create_proc_read_entry("sky_cpustate", 0, 0, cpustate_read_proc, NULL); + ret = misc_register(&cpustate_dev); + if (ret) { + printk(KERN_WARNING "sky_cpustate: Unable to register misc " + "device.\n"); + cpustate.set_addr = NULL; + cpustate.clr_addr = NULL; + return ret; + } + + proc_de = create_proc_read_entry("sky_cpustate", 0, 0, + cpustate_read_proc, NULL); + if (proc_de == NULL) + printk(KERN_WARNING "sky_cpustate: Unable to create proc " + "dir entry\n"); printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); return 0; } + static int hdpu_cpustate_remove(struct device *ddev) { - cpustate.set_addr = 0; - cpustate.clr_addr = 0; + cpustate.set_addr = NULL; + cpustate.clr_addr = NULL; remove_proc_entry("sky_cpustate", NULL); misc_deregister(&cpustate_dev); -- GitLab From 31bbf8f5d55c706f2e429f7cfa7b339a332e785e Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan <adobriyan@gmail.com> Date: Sat, 10 Sep 2005 00:26:34 -0700 Subject: [PATCH 366/563] [PATCH] sb16_csp: remove home-grown le??_to_cpu macros Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- sound/isa/sb/sb16_csp.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index b62920eead3db..4f1fad49dff46 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -42,8 +42,6 @@ MODULE_LICENSE("GPL"); #else #define CSP_HDR_VALUE(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24)) #endif -#define LE_SHORT(v) le16_to_cpu(v) -#define LE_INT(v) le32_to_cpu(v) #define RIFF_HEADER CSP_HDR_VALUE('R', 'I', 'F', 'F') #define CSP__HEADER CSP_HDR_VALUE('C', 'S', 'P', ' ') @@ -316,12 +314,12 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user if (copy_from_user(&file_h, data_ptr, sizeof(file_h))) return -EFAULT; if ((file_h.name != RIFF_HEADER) || - (LE_INT(file_h.len) >= SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE - sizeof(file_h))) { + (le32_to_cpu(file_h.len) >= SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE - sizeof(file_h))) { snd_printd("%s: Invalid RIFF header\n", __FUNCTION__); return -EINVAL; } data_ptr += sizeof(file_h); - data_end = data_ptr + LE_INT(file_h.len); + data_end = data_ptr + le32_to_cpu(file_h.len); if (copy_from_user(&item_type, data_ptr, sizeof(item_type))) return -EFAULT; @@ -331,7 +329,7 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user } data_ptr += sizeof (item_type); - for (; data_ptr < data_end; data_ptr += LE_INT(item_h.len)) { + for (; data_ptr < data_end; data_ptr += le32_to_cpu(item_h.len)) { if (copy_from_user(&item_h, data_ptr, sizeof(item_h))) return -EFAULT; data_ptr += sizeof(item_h); @@ -344,7 +342,7 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user case FUNC_HEADER: if (copy_from_user(&funcdesc_h, data_ptr + sizeof(item_type), sizeof(funcdesc_h))) return -EFAULT; - func_nr = LE_SHORT(funcdesc_h.func_nr); + func_nr = le16_to_cpu(funcdesc_h.func_nr); break; case CODE_HEADER: if (func_nr != info.func_req) @@ -370,11 +368,11 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user if (code_h.name != INIT_HEADER) break; data_ptr += sizeof(code_h); - err = snd_sb_csp_load_user(p, data_ptr, LE_INT(code_h.len), + err = snd_sb_csp_load_user(p, data_ptr, le32_to_cpu(code_h.len), SNDRV_SB_CSP_LOAD_INITBLOCK); if (err) return err; - data_ptr += LE_INT(code_h.len); + data_ptr += le32_to_cpu(code_h.len); } /* main microcode block */ if (copy_from_user(&code_h, data_ptr, sizeof(code_h))) @@ -386,17 +384,17 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user } data_ptr += sizeof(code_h); err = snd_sb_csp_load_user(p, data_ptr, - LE_INT(code_h.len), 0); + le32_to_cpu(code_h.len), 0); if (err) return err; /* fill in codec header */ strlcpy(p->codec_name, info.codec_name, sizeof(p->codec_name)); p->func_nr = func_nr; - p->mode = LE_SHORT(funcdesc_h.flags_play_rec); - switch (LE_SHORT(funcdesc_h.VOC_type)) { + p->mode = le16_to_cpu(funcdesc_h.flags_play_rec); + switch (le16_to_cpu(funcdesc_h.VOC_type)) { case 0x0001: /* QSound decoder */ - if (LE_SHORT(funcdesc_h.flags_play_rec) == SNDRV_SB_CSP_MODE_DSP_WRITE) { + if (le16_to_cpu(funcdesc_h.flags_play_rec) == SNDRV_SB_CSP_MODE_DSP_WRITE) { if (snd_sb_qsound_build(p) == 0) /* set QSound flag and clear all other mode flags */ p->mode = SNDRV_SB_CSP_MODE_QSOUND; @@ -426,12 +424,12 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user p->mode = 0; snd_printd("%s: Unsupported CSP codec type: 0x%04x\n", __FUNCTION__, - LE_SHORT(funcdesc_h.VOC_type)); + le16_to_cpu(funcdesc_h.VOC_type)); return -EINVAL; } - p->acc_channels = LE_SHORT(funcdesc_h.flags_stereo_mono); - p->acc_width = LE_SHORT(funcdesc_h.flags_16bit_8bit); - p->acc_rates = LE_SHORT(funcdesc_h.flags_rates); + p->acc_channels = le16_to_cpu(funcdesc_h.flags_stereo_mono); + p->acc_width = le16_to_cpu(funcdesc_h.flags_16bit_8bit); + p->acc_rates = le16_to_cpu(funcdesc_h.flags_rates); /* Decouple CSP from IRQ and DMAREQ lines */ spin_lock_irqsave(&p->chip->reg_lock, flags); -- GitLab From dfc866e5059561cc79a0cc1c68ff1492f4c78508 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan <adobriyan@gmail.com> Date: Sat, 10 Sep 2005 00:26:35 -0700 Subject: [PATCH 367/563] [PATCH] sb16_csp: untypedef Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- sound/isa/sb/sb16_csp.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 4f1fad49dff46..d64790bcd831a 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -54,20 +54,20 @@ MODULE_LICENSE("GPL"); /* * RIFF data format */ -typedef struct riff_header { +struct riff_header { __u32 name; __u32 len; -} riff_header_t; +}; -typedef struct desc_header { - riff_header_t info; +struct desc_header { + struct riff_header info; __u16 func_nr; __u16 VOC_type; __u16 flags_play_rec; __u16 flags_16bit_8bit; __u16 flags_stereo_mono; __u16 flags_rates; -} desc_header_t; +}; /* * prototypes @@ -300,9 +300,9 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user unsigned char __user *data_end; unsigned short func_nr = 0; - riff_header_t file_h, item_h, code_h; + struct riff_header file_h, item_h, code_h; __u32 item_type; - desc_header_t funcdesc_h; + struct desc_header funcdesc_h; unsigned long flags; int err; -- GitLab From b2d550736f8b2186b8ef7e206d0bfbfec2238ae8 Mon Sep 17 00:00:00 2001 From: Victor Fusco <victor@cetuc.puc-rio.br> Date: Sat, 10 Sep 2005 00:26:36 -0700 Subject: [PATCH 368/563] [PATCH] mm/slab: fix sparse warnings Fix the sparse warning "implicit cast to nocast type" Signed-off-by: Victor Fusco <victor@cetuc.puc-rio.br> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/slab.h | 3 ++- mm/slab.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/linux/slab.h b/include/linux/slab.h index 42a6bea58af36..1f356f3bbc646 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -118,7 +118,8 @@ extern void kfree(const void *); extern unsigned int ksize(const void *); #ifdef CONFIG_NUMA -extern void *kmem_cache_alloc_node(kmem_cache_t *, int flags, int node); +extern void *kmem_cache_alloc_node(kmem_cache_t *, + unsigned int __nocast flags, int node); extern void *kmalloc_node(size_t size, unsigned int __nocast flags, int node); #else static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int node) diff --git a/mm/slab.c b/mm/slab.c index 05a391059fe1d..9e876d6dfad97 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1720,7 +1720,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, cachep->objsize = size; if (flags & CFLGS_OFF_SLAB) - cachep->slabp_cache = kmem_find_general_cachep(slab_size,0); + cachep->slabp_cache = kmem_find_general_cachep(slab_size, 0u); cachep->ctor = ctor; cachep->dtor = dtor; cachep->name = name; @@ -2839,7 +2839,7 @@ int fastcall kmem_ptr_validate(kmem_cache_t *cachep, void *ptr) * New and improved: it will now make sure that the object gets * put on the correct node list so that there is no false sharing. */ -void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int nodeid) +void *kmem_cache_alloc_node(kmem_cache_t *cachep, unsigned int __nocast flags, int nodeid) { unsigned long save_flags; void *ptr; -- GitLab From 621a4d1a823e1ec631fbfbe6e53ad036e2d2abc6 Mon Sep 17 00:00:00 2001 From: Victor Fusco <victor@cetuc.puc-rio.br> Date: Sat, 10 Sep 2005 00:26:38 -0700 Subject: [PATCH 369/563] [PATCH] char/n_tty: fix sparse warnings (__nocast type) Fix the sparse warning "implicit cast to nocast type" Signed-off-by: Victor Fusco <victor@cetuc.puc-rio.br> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/n_tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 09103b3d8f05a..c9bdf544ed2cd 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -62,7 +62,7 @@ static inline unsigned char *alloc_buf(void) { - int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + unsigned int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; if (PAGE_SIZE != N_TTY_BUF_SIZE) return kmalloc(N_TTY_BUF_SIZE, prio); -- GitLab From 417ef531415c070926b071b75fd1c1ac4b6e2f7e Mon Sep 17 00:00:00 2001 From: Randy Dunlap <rdunlap@xenotime.net> Date: Sat, 10 Sep 2005 00:26:39 -0700 Subject: [PATCH 370/563] [PATCH] kernel/acct: add kerneldoc for kernel/acct.c: - fix typos - add kerneldoc for non-static functions Signed-off-by: Randy Dunlap <rdunlap@xenotime.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/acct.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/kernel/acct.c b/kernel/acct.c index f70e6027cca97..b756f527497ea 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -165,7 +165,7 @@ static int check_free_space(struct file *file) } /* - * Close the old accouting file (if currently open) and then replace + * Close the old accounting file (if currently open) and then replace * it with file (if non-NULL). * * NOTE: acct_globals.lock MUST be held on entry and exit. @@ -199,11 +199,16 @@ static void acct_file_reopen(struct file *file) } } -/* - * sys_acct() is the only system call needed to implement process - * accounting. It takes the name of the file where accounting records - * should be written. If the filename is NULL, accounting will be - * shutdown. +/** + * sys_acct - enable/disable process accounting + * @name: file name for accounting records or NULL to shutdown accounting + * + * Returns 0 for success or negative errno values for failure. + * + * sys_acct() is the only system call needed to implement process + * accounting. It takes the name of the file where accounting records + * should be written. If the filename is NULL, accounting will be + * shutdown. */ asmlinkage long sys_acct(const char __user *name) { @@ -250,9 +255,12 @@ asmlinkage long sys_acct(const char __user *name) return (0); } -/* - * If the accouting is turned on for a file in the filesystem pointed - * to by sb, turn accouting off. +/** + * acct_auto_close - turn off a filesystem's accounting if it is on + * @sb: super block for the filesystem + * + * If the accounting is turned on for a file in the filesystem pointed + * to by sb, turn accounting off. */ void acct_auto_close(struct super_block *sb) { @@ -503,8 +511,11 @@ static void do_acct_process(long exitcode, struct file *file) set_fs(fs); } -/* +/** * acct_process - now just a wrapper around do_acct_process + * @exitcode: task exit code + * + * handles process accounting for an exiting task */ void acct_process(long exitcode) { @@ -530,9 +541,9 @@ void acct_process(long exitcode) } -/* - * acct_update_integrals - * - update mm integral fields in task_struct +/** + * acct_update_integrals - update mm integral fields in task_struct + * @tsk: task_struct for accounting */ void acct_update_integrals(struct task_struct *tsk) { @@ -547,9 +558,9 @@ void acct_update_integrals(struct task_struct *tsk) } } -/* - * acct_clear_integrals - * - clear the mm integral fields in task_struct +/** + * acct_clear_integrals - clear the mm integral fields in task_struct + * @tsk: task_struct whose accounting fields are cleared */ void acct_clear_integrals(struct task_struct *tsk) { -- GitLab From 2830e21eb3c600865245478cd7a28ae73191b6b7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner <tglx@linutronix.de> Date: Sat, 10 Sep 2005 00:26:40 -0700 Subject: [PATCH 371/563] [PATCH] PPC: C99 initializers for hw_interrupt_type structures Convert the initializers of hw_interrupt_type structures to C99 initializers. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ppc/syslib/cpc700_pic.c | 12 ++++-------- arch/ppc/syslib/i8259.c | 13 +++++-------- arch/ppc/syslib/open_pic2.c | 12 +++++------- arch/ppc/syslib/ppc403_pic.c | 11 ++++------- arch/ppc/syslib/xilinx_pic.c | 13 +++++-------- 5 files changed, 23 insertions(+), 38 deletions(-) diff --git a/arch/ppc/syslib/cpc700_pic.c b/arch/ppc/syslib/cpc700_pic.c index 774709807538d..75fe8eb106935 100644 --- a/arch/ppc/syslib/cpc700_pic.c +++ b/arch/ppc/syslib/cpc700_pic.c @@ -90,14 +90,10 @@ cpc700_mask_and_ack_irq(unsigned int irq) } static struct hw_interrupt_type cpc700_pic = { - "CPC700 PIC", - NULL, - NULL, - cpc700_unmask_irq, - cpc700_mask_irq, - cpc700_mask_and_ack_irq, - NULL, - NULL + .typename = "CPC700 PIC", + .enable = cpc700_unmask_irq, + .disable = cpc700_mask_irq, + .ack = cpc700_mask_and_ack_irq, }; __init static void diff --git a/arch/ppc/syslib/i8259.c b/arch/ppc/syslib/i8259.c index b9391e6501412..5c7908c20e43e 100644 --- a/arch/ppc/syslib/i8259.c +++ b/arch/ppc/syslib/i8259.c @@ -129,14 +129,11 @@ static void i8259_end_irq(unsigned int irq) } struct hw_interrupt_type i8259_pic = { - " i8259 ", - NULL, - NULL, - i8259_unmask_irq, - i8259_mask_irq, - i8259_mask_and_ack_irq, - i8259_end_irq, - NULL + .typename = " i8259 ", + .enable = i8259_unmask_irq, + .disable = i8259_mask_irq, + .ack = i8259_mask_and_ack_irq, + .end = i8259_end_irq, }; static struct resource pic1_iores = { diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c index 7e272c51a4973..2e0ea92144f6b 100644 --- a/arch/ppc/syslib/open_pic2.c +++ b/arch/ppc/syslib/open_pic2.c @@ -82,13 +82,11 @@ static void openpic2_end_irq(unsigned int irq_nr); static void openpic2_ack_irq(unsigned int irq_nr); struct hw_interrupt_type open_pic2 = { - " OpenPIC2 ", - NULL, - NULL, - openpic2_enable_irq, - openpic2_disable_irq, - openpic2_ack_irq, - openpic2_end_irq, + .typename = " OpenPIC2 ", + .enable = openpic2_enable_irq, + .disable = openpic2_disable_irq, + .ack = openpic2_ack_irq, + .end = openpic2_end_irq, }; /* diff --git a/arch/ppc/syslib/ppc403_pic.c b/arch/ppc/syslib/ppc403_pic.c index 06cb0af2a58d8..ce4d1deb86e93 100644 --- a/arch/ppc/syslib/ppc403_pic.c +++ b/arch/ppc/syslib/ppc403_pic.c @@ -34,13 +34,10 @@ static void ppc403_aic_disable(unsigned int irq); static void ppc403_aic_disable_and_ack(unsigned int irq); static struct hw_interrupt_type ppc403_aic = { - "403GC AIC", - NULL, - NULL, - ppc403_aic_enable, - ppc403_aic_disable, - ppc403_aic_disable_and_ack, - 0 + .typename = "403GC AIC", + .enable = ppc403_aic_enable, + .disable = ppc403_aic_disable, + .ack = ppc403_aic_disable_and_ack, }; int diff --git a/arch/ppc/syslib/xilinx_pic.c b/arch/ppc/syslib/xilinx_pic.c index e0bd66f0847a5..2cbcad278cefc 100644 --- a/arch/ppc/syslib/xilinx_pic.c +++ b/arch/ppc/syslib/xilinx_pic.c @@ -79,14 +79,11 @@ xilinx_intc_end(unsigned int irq) } static struct hw_interrupt_type xilinx_intc = { - "Xilinx Interrupt Controller", - NULL, - NULL, - xilinx_intc_enable, - xilinx_intc_disable, - xilinx_intc_disable_and_ack, - xilinx_intc_end, - 0 + .typename = "Xilinx Interrupt Controller", + .enable = xilinx_intc_enable, + .disable = xilinx_intc_disable, + .ack = xilinx_intc_disable_and_ack, + .end = xilinx_intc_end, }; int -- GitLab From 08d0fd07c3f0b6e561260f0b078d03d6fa1ac59f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner <tglx@linutronix.de> Date: Sat, 10 Sep 2005 00:26:42 -0700 Subject: [PATCH 372/563] [PATCH] SH: C99 initializers for hw_interrupt_type structures Convert the initializers of hw_interrupt_type structures to C99 initializers. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/sh/boards/adx/irq_maskreg.c | 14 ++++++------ arch/sh/boards/bigsur/irq.c | 28 ++++++++++++------------ arch/sh/boards/cqreek/irq.c | 14 ++++++------ arch/sh/boards/harp/irq.c | 14 ++++++------ arch/sh/boards/overdrive/irq.c | 14 ++++++------ arch/sh/boards/renesas/hs7751rvoip/irq.c | 14 ++++++------ arch/sh/boards/renesas/rts7751r2d/irq.c | 14 ++++++------ arch/sh/boards/renesas/systemh/irq.c | 14 ++++++------ arch/sh/boards/superh/microdev/irq.c | 14 ++++++------ arch/sh/cchips/voyagergx/irq.c | 14 ++++++------ arch/sh/kernel/cpu/irq_imask.c | 14 ++++++------ arch/sh/kernel/cpu/irq_ipr.c | 28 ++++++++++++------------ arch/sh/kernel/cpu/sh4/irq_intc2.c | 14 ++++++------ 13 files changed, 105 insertions(+), 105 deletions(-) diff --git a/arch/sh/boards/adx/irq_maskreg.c b/arch/sh/boards/adx/irq_maskreg.c index ca91bb0f1f5c0..c0973f8d57bae 100644 --- a/arch/sh/boards/adx/irq_maskreg.c +++ b/arch/sh/boards/adx/irq_maskreg.c @@ -37,13 +37,13 @@ static void end_maskreg_irq(unsigned int irq); /* hw_interrupt_type */ static struct hw_interrupt_type maskreg_irq_type = { - " Mask Register", - startup_maskreg_irq, - shutdown_maskreg_irq, - enable_maskreg_irq, - disable_maskreg_irq, - mask_and_ack_maskreg, - end_maskreg_irq + .typename = " Mask Register", + .startup = startup_maskreg_irq, + .shutdown = shutdown_maskreg_irq, + .enable = enable_maskreg_irq, + .disable = disable_maskreg_irq, + .ack = mask_and_ack_maskreg, + .end = end_maskreg_irq }; /* actual implementatin */ diff --git a/arch/sh/boards/bigsur/irq.c b/arch/sh/boards/bigsur/irq.c index c188fc32dc9a8..6ddbcc77244da 100644 --- a/arch/sh/boards/bigsur/irq.c +++ b/arch/sh/boards/bigsur/irq.c @@ -228,23 +228,23 @@ static void shutdown_bigsur_irq(unsigned int irq) /* Define the IRQ structures for the L1 and L2 IRQ types */ static struct hw_interrupt_type bigsur_l1irq_type = { - "BigSur-CPLD-Level1-IRQ", - startup_bigsur_irq, - shutdown_bigsur_irq, - enable_bigsur_l1irq, - disable_bigsur_l1irq, - mask_and_ack_bigsur, - end_bigsur_irq + .typename = "BigSur-CPLD-Level1-IRQ", + .startup = startup_bigsur_irq, + .shutdown = shutdown_bigsur_irq, + .enable = enable_bigsur_l1irq, + .disable = disable_bigsur_l1irq, + .ack = mask_and_ack_bigsur, + .end = end_bigsur_irq }; static struct hw_interrupt_type bigsur_l2irq_type = { - "BigSur-CPLD-Level2-IRQ", - startup_bigsur_irq, - shutdown_bigsur_irq, - enable_bigsur_l2irq, - disable_bigsur_l2irq, - mask_and_ack_bigsur, - end_bigsur_irq + .typename = "BigSur-CPLD-Level2-IRQ", + .startup = startup_bigsur_irq, + .shutdown =shutdown_bigsur_irq, + .enable = enable_bigsur_l2irq, + .disable = disable_bigsur_l2irq, + .ack = mask_and_ack_bigsur, + .end = end_bigsur_irq }; diff --git a/arch/sh/boards/cqreek/irq.c b/arch/sh/boards/cqreek/irq.c index fa6cfe5a20a70..d1da0d844567f 100644 --- a/arch/sh/boards/cqreek/irq.c +++ b/arch/sh/boards/cqreek/irq.c @@ -83,13 +83,13 @@ static void shutdown_cqreek_irq(unsigned int irq) } static struct hw_interrupt_type cqreek_irq_type = { - "CqREEK-IRQ", - startup_cqreek_irq, - shutdown_cqreek_irq, - enable_cqreek_irq, - disable_cqreek_irq, - mask_and_ack_cqreek, - end_cqreek_irq + .typename = "CqREEK-IRQ", + .startup = startup_cqreek_irq, + .shutdown = shutdown_cqreek_irq, + .enable = enable_cqreek_irq, + .disable = disable_cqreek_irq, + .ack = mask_and_ack_cqreek, + .end = end_cqreek_irq }; int cqreek_has_ide, cqreek_has_isa; diff --git a/arch/sh/boards/harp/irq.c b/arch/sh/boards/harp/irq.c index acd58489970f4..52d0ba39031b7 100644 --- a/arch/sh/boards/harp/irq.c +++ b/arch/sh/boards/harp/irq.c @@ -39,13 +39,13 @@ static unsigned int startup_harp_irq(unsigned int irq) } static struct hw_interrupt_type harp_irq_type = { - "Harp-IRQ", - startup_harp_irq, - shutdown_harp_irq, - enable_harp_irq, - disable_harp_irq, - mask_and_ack_harp, - end_harp_irq + .typename = "Harp-IRQ", + .startup = startup_harp_irq, + .shutdown = shutdown_harp_irq, + .enable = enable_harp_irq, + .disable = disable_harp_irq, + .ack = mask_and_ack_harp, + .end = end_harp_irq }; static void disable_harp_irq(unsigned int irq) diff --git a/arch/sh/boards/overdrive/irq.c b/arch/sh/boards/overdrive/irq.c index 23adc6be71e72..715e8feb3a687 100644 --- a/arch/sh/boards/overdrive/irq.c +++ b/arch/sh/boards/overdrive/irq.c @@ -86,13 +86,13 @@ static unsigned int startup_od_irq(unsigned int irq) } static struct hw_interrupt_type od_irq_type = { - "Overdrive-IRQ", - startup_od_irq, - shutdown_od_irq, - enable_od_irq, - disable_od_irq, - mask_and_ack_od, - end_od_irq + .typename = "Overdrive-IRQ", + .startup = startup_od_irq, + .shutdown = shutdown_od_irq, + .enable = enable_od_irq, + .disable = disable_od_irq, + .ack = mask_and_ack_od, + .end = end_od_irq }; static void disable_od_irq(unsigned int irq) diff --git a/arch/sh/boards/renesas/hs7751rvoip/irq.c b/arch/sh/boards/renesas/hs7751rvoip/irq.c index a7921f67a35fc..ed4c5b50ea45e 100644 --- a/arch/sh/boards/renesas/hs7751rvoip/irq.c +++ b/arch/sh/boards/renesas/hs7751rvoip/irq.c @@ -74,13 +74,13 @@ static void end_hs7751rvoip_irq(unsigned int irq) } static struct hw_interrupt_type hs7751rvoip_irq_type = { - "HS7751RVoIP IRQ", - startup_hs7751rvoip_irq, - shutdown_hs7751rvoip_irq, - enable_hs7751rvoip_irq, - disable_hs7751rvoip_irq, - ack_hs7751rvoip_irq, - end_hs7751rvoip_irq, + .typename = "HS7751RVoIP IRQ", + .startup = startup_hs7751rvoip_irq, + .shutdown = shutdown_hs7751rvoip_irq, + .enable = enable_hs7751rvoip_irq, + .disable = disable_hs7751rvoip_irq, + .ack = ack_hs7751rvoip_irq, + .end = end_hs7751rvoip_irq, }; static void make_hs7751rvoip_irq(unsigned int irq) diff --git a/arch/sh/boards/renesas/rts7751r2d/irq.c b/arch/sh/boards/renesas/rts7751r2d/irq.c index 95717f4f1e2d0..d36c9374aed1d 100644 --- a/arch/sh/boards/renesas/rts7751r2d/irq.c +++ b/arch/sh/boards/renesas/rts7751r2d/irq.c @@ -88,13 +88,13 @@ static void end_rts7751r2d_irq(unsigned int irq) } static struct hw_interrupt_type rts7751r2d_irq_type = { - "RTS7751R2D IRQ", - startup_rts7751r2d_irq, - shutdown_rts7751r2d_irq, - enable_rts7751r2d_irq, - disable_rts7751r2d_irq, - ack_rts7751r2d_irq, - end_rts7751r2d_irq, + .typename = "RTS7751R2D IRQ", + .startup = startup_rts7751r2d_irq, + .shutdown = shutdown_rts7751r2d_irq, + .enable = enable_rts7751r2d_irq, + .disable = disable_rts7751r2d_irq, + .ack = ack_rts7751r2d_irq, + .end = end_rts7751r2d_irq, }; static void make_rts7751r2d_irq(unsigned int irq) diff --git a/arch/sh/boards/renesas/systemh/irq.c b/arch/sh/boards/renesas/systemh/irq.c index 5675a4134eee8..7a2eb10edb563 100644 --- a/arch/sh/boards/renesas/systemh/irq.c +++ b/arch/sh/boards/renesas/systemh/irq.c @@ -35,13 +35,13 @@ static void end_systemh_irq(unsigned int irq); /* hw_interrupt_type */ static struct hw_interrupt_type systemh_irq_type = { - " SystemH Register", - startup_systemh_irq, - shutdown_systemh_irq, - enable_systemh_irq, - disable_systemh_irq, - mask_and_ack_systemh, - end_systemh_irq + .typename = " SystemH Register", + .startup = startup_systemh_irq, + .shutdown = shutdown_systemh_irq, + .enable = enable_systemh_irq, + .disable = disable_systemh_irq, + .ack = mask_and_ack_systemh, + .end = end_systemh_irq }; static unsigned int startup_systemh_irq(unsigned int irq) diff --git a/arch/sh/boards/superh/microdev/irq.c b/arch/sh/boards/superh/microdev/irq.c index 1298883eca4be..1395c1e65da45 100644 --- a/arch/sh/boards/superh/microdev/irq.c +++ b/arch/sh/boards/superh/microdev/irq.c @@ -83,13 +83,13 @@ static unsigned int startup_microdev_irq(unsigned int irq) } static struct hw_interrupt_type microdev_irq_type = { - "MicroDev-IRQ", - startup_microdev_irq, - shutdown_microdev_irq, - enable_microdev_irq, - disable_microdev_irq, - mask_and_ack_microdev, - end_microdev_irq + .typename = "MicroDev-IRQ", + .startup = startup_microdev_irq, + .shutdown = shutdown_microdev_irq, + .enable = enable_microdev_irq, + .disable = disable_microdev_irq, + .ack = mask_and_ack_microdev, + .end = end_microdev_irq }; static void disable_microdev_irq(unsigned int irq) diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c index 3079234cb65b3..1b6ac523b4584 100644 --- a/arch/sh/cchips/voyagergx/irq.c +++ b/arch/sh/cchips/voyagergx/irq.c @@ -87,13 +87,13 @@ static void shutdown_voyagergx_irq(unsigned int irq) } static struct hw_interrupt_type voyagergx_irq_type = { - "VOYAGERGX-IRQ", - startup_voyagergx_irq, - shutdown_voyagergx_irq, - enable_voyagergx_irq, - disable_voyagergx_irq, - mask_and_ack_voyagergx, - end_voyagergx_irq, + .typename = "VOYAGERGX-IRQ", + .startup = startup_voyagergx_irq, + .shutdown = shutdown_voyagergx_irq, + .enable = enable_voyagergx_irq, + .disable = disable_voyagergx_irq, + .ack = mask_and_ack_voyagergx, + .end = end_voyagergx_irq, }; static irqreturn_t voyagergx_interrupt(int irq, void *dev_id, struct pt_regs *regs) diff --git a/arch/sh/kernel/cpu/irq_imask.c b/arch/sh/kernel/cpu/irq_imask.c index f76901e732fb8..a963d00a971e6 100644 --- a/arch/sh/kernel/cpu/irq_imask.c +++ b/arch/sh/kernel/cpu/irq_imask.c @@ -46,13 +46,13 @@ static unsigned int startup_imask_irq(unsigned int irq) } static struct hw_interrupt_type imask_irq_type = { - "SR.IMASK", - startup_imask_irq, - shutdown_imask_irq, - enable_imask_irq, - disable_imask_irq, - mask_and_ack_imask, - end_imask_irq + .typename = "SR.IMASK", + .startup = startup_imask_irq, + .shutdown = shutdown_imask_irq, + .enable = enable_imask_irq, + .disable = disable_imask_irq, + .ack = mask_and_ack_imask, + .end = end_imask_irq }; void static inline set_interrupt_registers(int ip) diff --git a/arch/sh/kernel/cpu/irq_ipr.c b/arch/sh/kernel/cpu/irq_ipr.c index 7ea3d2d030e55..71f92096132b3 100644 --- a/arch/sh/kernel/cpu/irq_ipr.c +++ b/arch/sh/kernel/cpu/irq_ipr.c @@ -48,13 +48,13 @@ static unsigned int startup_ipr_irq(unsigned int irq) } static struct hw_interrupt_type ipr_irq_type = { - "IPR-IRQ", - startup_ipr_irq, - shutdown_ipr_irq, - enable_ipr_irq, - disable_ipr_irq, - mask_and_ack_ipr, - end_ipr_irq + .typename = "IPR-IRQ", + .startup = startup_ipr_irq, + .shutdown = shutdown_ipr_irq, + .enable = enable_ipr_irq, + .disable = disable_ipr_irq, + .ack = mask_and_ack_ipr, + .end = end_ipr_irq }; static void disable_ipr_irq(unsigned int irq) @@ -142,13 +142,13 @@ static unsigned int startup_pint_irq(unsigned int irq) } static struct hw_interrupt_type pint_irq_type = { - "PINT-IRQ", - startup_pint_irq, - shutdown_pint_irq, - enable_pint_irq, - disable_pint_irq, - mask_and_ack_pint, - end_pint_irq + .typename = "PINT-IRQ", + .startup = startup_pint_irq, + .shutdown = shutdown_pint_irq, + .enable = enable_pint_irq, + .disable = disable_pint_irq, + .ack = mask_and_ack_pint, + .end = end_pint_irq }; static void disable_pint_irq(unsigned int irq) diff --git a/arch/sh/kernel/cpu/sh4/irq_intc2.c b/arch/sh/kernel/cpu/sh4/irq_intc2.c index 099ebbf897457..f6b16ba01932f 100644 --- a/arch/sh/kernel/cpu/sh4/irq_intc2.c +++ b/arch/sh/kernel/cpu/sh4/irq_intc2.c @@ -48,13 +48,13 @@ static unsigned int startup_intc2_irq(unsigned int irq) } static struct hw_interrupt_type intc2_irq_type = { - "INTC2-IRQ", - startup_intc2_irq, - shutdown_intc2_irq, - enable_intc2_irq, - disable_intc2_irq, - mask_and_ack_intc2, - end_intc2_irq + .typename = "INTC2-IRQ", + .startup = startup_intc2_irq, + .shutdown = shutdown_intc2_irq, + .enable = enable_intc2_irq, + .disable = disable_intc2_irq, + .ack = mask_and_ack_intc2, + .end = end_intc2_irq }; static void disable_intc2_irq(unsigned int irq) -- GitLab From aecd4568ac8abcedc1e46fc3804439ac8e1b8ff4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner <tglx@linutronix.de> Date: Sat, 10 Sep 2005 00:26:43 -0700 Subject: [PATCH 373/563] [PATCH] V850: C99 initializers for hw_interrupt_type structures Convert the initializers of hw_interrupt_type structures to C99 initializers. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/v850/kernel/irq.c | 14 +++++++------- arch/v850/kernel/setup.c | 14 +++++++------- arch/v850/kernel/sim.c | 14 +++++++------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/arch/v850/kernel/irq.c b/arch/v850/kernel/irq.c index 336cbf21dc8ff..9e85969ba9767 100644 --- a/arch/v850/kernel/irq.c +++ b/arch/v850/kernel/irq.c @@ -67,13 +67,13 @@ static void ack_none(unsigned int irq) #define end_none enable_none struct hw_interrupt_type no_irq_type = { - "none", - startup_none, - shutdown_none, - enable_none, - disable_none, - ack_none, - end_none + .typename = "none", + .startup = startup_none, + .shutdown = shutdown_none, + .enable = enable_none, + .disable = disable_none, + .ack = ack_none, + .end = end_none }; volatile unsigned long irq_err_count, spurious_count; diff --git a/arch/v850/kernel/setup.c b/arch/v850/kernel/setup.c index abd48409dcca5..62bdb8d29fc05 100644 --- a/arch/v850/kernel/setup.c +++ b/arch/v850/kernel/setup.c @@ -138,13 +138,13 @@ static void nmi_end (unsigned irq) } static struct hw_interrupt_type nmi_irq_type = { - "NMI", - irq_zero, /* startup */ - irq_nop, /* shutdown */ - irq_nop, /* enable */ - irq_nop, /* disable */ - irq_nop, /* ack */ - nmi_end, /* end */ + .typename = "NMI", + .startup = irq_zero, /* startup */ + .shutdown = irq_nop, /* shutdown */ + .enable = irq_nop, /* enable */ + .disable = irq_nop, /* disable */ + .ack = irq_nop, /* ack */ + .end = nmi_end, /* end */ }; void __init init_IRQ (void) diff --git a/arch/v850/kernel/sim.c b/arch/v850/kernel/sim.c index e2cc5580fa2a1..17049aaa8f118 100644 --- a/arch/v850/kernel/sim.c +++ b/arch/v850/kernel/sim.c @@ -73,13 +73,13 @@ static void irq_nop (unsigned irq) { } static unsigned irq_zero (unsigned irq) { return 0; } static struct hw_interrupt_type sim_irq_type = { - "IRQ", - irq_zero, /* startup */ - irq_nop, /* shutdown */ - irq_nop, /* enable */ - irq_nop, /* disable */ - irq_nop, /* ack */ - irq_nop, /* end */ + .typename = "IRQ", + .startup = irq_zero, /* startup */ + .shutdown = irq_nop, /* shutdown */ + .enable = irq_nop, /* enable */ + .disable = irq_nop, /* disable */ + .ack = irq_nop, /* ack */ + .end = irq_nop, /* end */ }; void __init mach_init_irqs (void) -- GitLab From c05e0664e1d080344d6ce346de43e51895541e21 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner <tglx@linutronix.de> Date: Sat, 10 Sep 2005 00:26:44 -0700 Subject: [PATCH 374/563] [PATCH] SH64: C99 initializers for hw_interrupt_type structures Convert the initializers of hw_interrupt_type structures to C99 initializers. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/sh64/kernel/irq_intc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/sh64/kernel/irq_intc.c b/arch/sh64/kernel/irq_intc.c index 43f88f3a78b0d..fc99bf4e362c9 100644 --- a/arch/sh64/kernel/irq_intc.c +++ b/arch/sh64/kernel/irq_intc.c @@ -107,13 +107,13 @@ static void mask_and_ack_intc(unsigned int); static void end_intc_irq(unsigned int irq); static struct hw_interrupt_type intc_irq_type = { - "INTC", - startup_intc_irq, - shutdown_intc_irq, - enable_intc_irq, - disable_intc_irq, - mask_and_ack_intc, - end_intc_irq + .typename = "INTC", + .startup = startup_intc_irq, + .shutdown = shutdown_intc_irq, + .enable = enable_intc_irq, + .disable = disable_intc_irq, + .ack = mask_and_ack_intc, + .end = end_intc_irq }; static int irlm; /* IRL mode */ -- GitLab From e776eba0feaea9a3eba7aff73f50701b9804b57f Mon Sep 17 00:00:00 2001 From: Pekka J Enberg <penberg@cs.Helsinki.FI> Date: Sat, 10 Sep 2005 00:26:44 -0700 Subject: [PATCH 375/563] [PATCH] Add kerneldoc reference to CodingStyle Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/CodingStyle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index f25b3953f5139..22e5f9036f3c1 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -236,6 +236,9 @@ ugly), but try to avoid excess. Instead, put the comments at the head of the function, telling people what it does, and possibly WHY it does it. +When commenting the kernel API functions, please use the kerneldoc format. +See the files Documentation/kernel-doc-nano-HOWTO.txt and scripts/kernel-doc +for details. Chapter 8: You've made a mess of it -- GitLab From 9de75d110c9681d4aaa7fe87b8db99d5562012a2 Mon Sep 17 00:00:00 2001 From: Victor Fusco <victor@cetuc.puc-rio.br> Date: Sat, 10 Sep 2005 00:26:46 -0700 Subject: [PATCH 376/563] [PATCH] mm/swap_state: Fix "nocast type" warnings Fix the sparse warning "implicit cast to nocast type" Signed-off-by: Victor Fusco <victor@cetuc.puc-rio.br> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- mm/swap_state.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/swap_state.c b/mm/swap_state.c index 029e56eb5e77c..adbc2b426c2f1 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -67,8 +67,8 @@ void show_swap_cache_info(void) * __add_to_swap_cache resembles add_to_page_cache on swapper_space, * but sets SwapCache flag and private instead of mapping and index. */ -static int __add_to_swap_cache(struct page *page, - swp_entry_t entry, int gfp_mask) +static int __add_to_swap_cache(struct page *page, swp_entry_t entry, + unsigned int __nocast gfp_mask) { int error; -- GitLab From d533f671852cc4e481ea7070aa1a3b6fc75b8e44 Mon Sep 17 00:00:00 2001 From: Tobias Klauser <tklauser@nuerscht.ch> Date: Sat, 10 Sep 2005 00:26:46 -0700 Subject: [PATCH 377/563] [PATCH] Spelling fixes for Documentation/ The attached patch fixes the following spelling errors in Documentation/ - double "the" - Several misspellings of function/functionality - infomation - memeory - Recieved - wether and possibly others which I forgot ;-) Trailing whitespaces on the same line as the typo are also deleted. Signed-off-by: Tobias Klauser <tklauser@nuerscht.ch> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/00-INDEX | 2 +- Documentation/DMA-API.txt | 2 +- Documentation/DocBook/journal-api.tmpl | 4 ++-- Documentation/DocBook/usb.tmpl | 2 +- Documentation/MSI-HOWTO.txt | 2 +- Documentation/cpu-freq/cpufreq-stats.txt | 2 +- Documentation/cpusets.txt | 2 +- Documentation/crypto/descore-readme.txt | 2 +- Documentation/ioctl/cdrom.txt | 2 +- Documentation/networking/bonding.txt | 4 ++-- Documentation/networking/wan-router.txt | 4 ++-- Documentation/powerpc/eeh-pci-error-recovery.txt | 2 +- Documentation/s390/s390dbf.txt | 2 +- Documentation/scsi/ibmmca.txt | 2 +- Documentation/sound/alsa/ALSA-Configuration.txt | 2 +- Documentation/uml/UserModeLinux-HOWTO.txt | 2 +- Documentation/usb/gadget_serial.txt | 2 +- Documentation/video4linux/Zoran | 2 +- 18 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index f6de52b010591..433cf5e9ae04b 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -277,7 +277,7 @@ tty.txt unicode.txt - info on the Unicode character/font mapping used in Linux. uml/ - - directory with infomation about User Mode Linux. + - directory with information about User Mode Linux. usb/ - directory with info regarding the Universal Serial Bus. video4linux/ diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt index 6ee3cd6134dfa..1af0f2d502206 100644 --- a/Documentation/DMA-API.txt +++ b/Documentation/DMA-API.txt @@ -121,7 +121,7 @@ pool's device. dma_addr_t addr); This puts memory back into the pool. The pool is what was passed to -the the pool allocation routine; the cpu and dma addresses are what +the pool allocation routine; the cpu and dma addresses are what were returned when that routine allocated the memory being freed. diff --git a/Documentation/DocBook/journal-api.tmpl b/Documentation/DocBook/journal-api.tmpl index 1ef6f43c6d8f6..341aaa4ce481a 100644 --- a/Documentation/DocBook/journal-api.tmpl +++ b/Documentation/DocBook/journal-api.tmpl @@ -116,7 +116,7 @@ filesystem. Almost. You still need to actually journal your filesystem changes, this is done by wrapping them into transactions. Additionally you -also need to wrap the modification of each of the the buffers +also need to wrap the modification of each of the buffers with calls to the journal layer, so it knows what the modifications you are actually making are. To do this use journal_start() which returns a transaction handle. @@ -128,7 +128,7 @@ and its counterpart journal_stop(), which indicates the end of a transaction are nestable calls, so you can reenter a transaction if necessary, but remember you must call journal_stop() the same number of times as journal_start() before the transaction is completed (or more accurately -leaves the the update phase). Ext3/VFS makes use of this feature to simplify +leaves the update phase). Ext3/VFS makes use of this feature to simplify quota support. </para> diff --git a/Documentation/DocBook/usb.tmpl b/Documentation/DocBook/usb.tmpl index f3ef0bf435e9e..705c442c7bf4c 100644 --- a/Documentation/DocBook/usb.tmpl +++ b/Documentation/DocBook/usb.tmpl @@ -841,7 +841,7 @@ usbdev_ioctl (int fd, int ifno, unsigned request, void *param) File modification time is not updated by this request. </para><para> Those struct members are from some interface descriptor - applying to the the current configuration. + applying to the current configuration. The interface number is the bInterfaceNumber value, and the altsetting number is the bAlternateSetting value. (This resets each endpoint in the interface.) diff --git a/Documentation/MSI-HOWTO.txt b/Documentation/MSI-HOWTO.txt index d5032eb480aa3..63edc5f847c45 100644 --- a/Documentation/MSI-HOWTO.txt +++ b/Documentation/MSI-HOWTO.txt @@ -430,7 +430,7 @@ which may result in system hang. The software driver of specific MSI-capable hardware is responsible for whether calling pci_enable_msi or not. A return of zero indicates the kernel successfully initializes the MSI/MSI-X capability structure of the -device funtion. The device function is now running on MSI/MSI-X mode. +device function. The device function is now running on MSI/MSI-X mode. 5.6 How to tell whether MSI/MSI-X is enabled on device function diff --git a/Documentation/cpu-freq/cpufreq-stats.txt b/Documentation/cpu-freq/cpufreq-stats.txt index e2d1e760b4ba3..6a82948ff4bd5 100644 --- a/Documentation/cpu-freq/cpufreq-stats.txt +++ b/Documentation/cpu-freq/cpufreq-stats.txt @@ -36,7 +36,7 @@ cpufreq stats provides following statistics (explained in detail below). All the statistics will be from the time the stats driver has been inserted to the time when a read of a particular statistic is done. Obviously, stats -driver will not have any information about the the frequcny transitions before +driver will not have any information about the frequency transitions before the stats driver insertion. -------------------------------------------------------------------------------- diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt index 47f4114fbf545..d17b7d2dd771e 100644 --- a/Documentation/cpusets.txt +++ b/Documentation/cpusets.txt @@ -277,7 +277,7 @@ rewritten to the 'tasks' file of its cpuset. This is done to avoid impacting the scheduler code in the kernel with a check for changes in a tasks processor placement. -There is an exception to the above. If hotplug funtionality is used +There is an exception to the above. If hotplug functionality is used to remove all the CPUs that are currently assigned to a cpuset, then the kernel will automatically update the cpus_allowed of all tasks attached to CPUs in that cpuset to allow all CPUs. When memory diff --git a/Documentation/crypto/descore-readme.txt b/Documentation/crypto/descore-readme.txt index 166474c2ee0bd..16e9e63507551 100644 --- a/Documentation/crypto/descore-readme.txt +++ b/Documentation/crypto/descore-readme.txt @@ -1,4 +1,4 @@ -Below is the orginal README file from the descore.shar package. +Below is the original README file from the descore.shar package. ------------------------------------------------------------------------------ des - fast & portable DES encryption & decryption. diff --git a/Documentation/ioctl/cdrom.txt b/Documentation/ioctl/cdrom.txt index 4ccdcc6fe3645..8ec32cc49eb10 100644 --- a/Documentation/ioctl/cdrom.txt +++ b/Documentation/ioctl/cdrom.txt @@ -878,7 +878,7 @@ DVD_READ_STRUCT Read structure error returns: EINVAL physical.layer_num exceeds number of layers - EIO Recieved invalid response from drive + EIO Received invalid response from drive diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 24d029455baad..a55f0f95b171a 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -1241,7 +1241,7 @@ traffic while still maintaining carrier on. If running SNMP agents, the bonding driver should be loaded before any network drivers participating in a bond. This requirement -is due to the the interface index (ipAdEntIfIndex) being associated to +is due to the interface index (ipAdEntIfIndex) being associated to the first interface found with a given IP address. That is, there is only one ipAdEntIfIndex for each IP address. For example, if eth0 and eth1 are slaves of bond0 and the driver for eth0 is loaded before the @@ -1937,7 +1937,7 @@ switches currently available support 802.3ad. If not explicitly configured (with ifconfig or ip link), the MAC address of the bonding device is taken from its first slave device. This MAC address is then passed to all following slaves and -remains persistent (even if the the first slave is removed) until the +remains persistent (even if the first slave is removed) until the bonding device is brought down or reconfigured. If you wish to change the MAC address, you can set it with diff --git a/Documentation/networking/wan-router.txt b/Documentation/networking/wan-router.txt index aea20cd2a56e0..c96897aa08b6b 100644 --- a/Documentation/networking/wan-router.txt +++ b/Documentation/networking/wan-router.txt @@ -355,7 +355,7 @@ REVISION HISTORY There is no functional difference between the two packages 2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE. - o Fixed a memeory leak for X25API + o Fixed a memory leak for X25API o Updated the X25API code for 2.2.X kernels. o Improved NEM handling. @@ -514,7 +514,7 @@ beta2-2.2.0 Jan 8 2001 o Patches for 2.4.0 kernel o Patches for 2.2.18 kernel o Minor updates to PPP and CHLDC drivers. - Note: No functinal difference. + Note: No functional difference. beta3-2.2.9 Jan 10 2001 o I missed the 2.2.18 kernel patches in beta2-2.2.0 diff --git a/Documentation/powerpc/eeh-pci-error-recovery.txt b/Documentation/powerpc/eeh-pci-error-recovery.txt index 2bfe71beec5b1..e75d7474322cd 100644 --- a/Documentation/powerpc/eeh-pci-error-recovery.txt +++ b/Documentation/powerpc/eeh-pci-error-recovery.txt @@ -134,7 +134,7 @@ pci_get_device_by_addr() will find the pci device associated with that address (if any). The default include/asm-ppc64/io.h macros readb(), inb(), insb(), -etc. include a check to see if the the i/o read returned all-0xff's. +etc. include a check to see if the i/o read returned all-0xff's. If so, these make a call to eeh_dn_check_failure(), which in turn asks the firmware if the all-ff's value is the sign of a true EEH error. If it is not, processing continues as normal. The grand diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt index e24fdeada9705..e321a8ed2a2d6 100644 --- a/Documentation/s390/s390dbf.txt +++ b/Documentation/s390/s390dbf.txt @@ -468,7 +468,7 @@ The hex_ascii view shows the data field in hex and ascii representation The raw view returns a bytestream as the debug areas are stored in memory. The sprintf view formats the debug entries in the same way as the sprintf -function would do. The sprintf event/expection fuctions write to the +function would do. The sprintf event/expection functions write to the debug entry a pointer to the format string (size = sizeof(long)) and for each vararg a long value. So e.g. for a debug entry with a format string plus two varargs one would need to allocate a (3 * sizeof(long)) diff --git a/Documentation/scsi/ibmmca.txt b/Documentation/scsi/ibmmca.txt index 2814491600ff4..2ffb3ae0ef4d1 100644 --- a/Documentation/scsi/ibmmca.txt +++ b/Documentation/scsi/ibmmca.txt @@ -344,7 +344,7 @@ /proc/scsi/ibmmca/<host_no>. ibmmca_proc_info() provides this information. This table is quite informative for interested users. It shows the load - of commands on the subsystem and wether you are running the bypassed + of commands on the subsystem and whether you are running the bypassed (software) or integrated (hardware) SCSI-command set (see below). The amount of accesses is shown. Read, write, modeselect is shown separately in order to help debugging problems with CD-ROMs or tapedrives. diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 5c49ba07e7096..ebfcdf28485f2 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1459,7 +1459,7 @@ devices where %i is sound card number from zero to seven. To auto-load an ALSA driver for OSS services, define the string 'sound-slot-%i' where %i means the slot number for OSS, which corresponds to the card index of ALSA. Usually, define this -as the the same card module. +as the same card module. An example configuration for a single emu10k1 card is like below: ----- /etc/modprobe.conf diff --git a/Documentation/uml/UserModeLinux-HOWTO.txt b/Documentation/uml/UserModeLinux-HOWTO.txt index 0c7b654fec996..544430e399802 100644 --- a/Documentation/uml/UserModeLinux-HOWTO.txt +++ b/Documentation/uml/UserModeLinux-HOWTO.txt @@ -2176,7 +2176,7 @@ If you want to access files on the host machine from inside UML, you can treat it as a separate machine and either nfs mount directories from the host or copy files into the virtual machine with scp or rcp. - However, since UML is running on the the host, it can access those + However, since UML is running on the host, it can access those files just like any other process and make them available inside the virtual machine without needing to use the network. diff --git a/Documentation/usb/gadget_serial.txt b/Documentation/usb/gadget_serial.txt index a938c3dd13d65..815f5c2301ffa 100644 --- a/Documentation/usb/gadget_serial.txt +++ b/Documentation/usb/gadget_serial.txt @@ -20,7 +20,7 @@ License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -This document and the the gadget serial driver itself are +This document and the gadget serial driver itself are Copyright (C) 2004 by Al Borchers (alborchers@steinerpoint.com). If you have questions, problems, or suggestions for this driver diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran index 01425c21986ba..52c94bd7dca1f 100644 --- a/Documentation/video4linux/Zoran +++ b/Documentation/video4linux/Zoran @@ -222,7 +222,7 @@ was introduced in 1991, is used in the DC10 old can generate: PAL , NTSC , SECAM The adv717x, should be able to produce PAL N. But you find nothing PAL N -specific in the the registers. Seem that you have to reuse a other standard +specific in the registers. Seem that you have to reuse a other standard to generate PAL N, maybe it would work if you use the PAL M settings. ========================== -- GitLab From 00b61f51922e432fd92a482ba1e0b5f8f326ef46 Mon Sep 17 00:00:00 2001 From: Victor Fusco <victor@cetuc.puc-rio.br> Date: Sat, 10 Sep 2005 00:26:48 -0700 Subject: [PATCH 378/563] [PATCH] lib/radix-tree: Fix "nocast type" warnings Fix the sparse warning "implicit cast to nocast type" Signed-off-by: Victor Fusco <victor@cetuc.puc-rio.br> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/radix-tree.h | 4 ++-- lib/radix-tree.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index 8081a281fa5eb..9c51917b1cce1 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -24,7 +24,7 @@ struct radix_tree_root { unsigned int height; - int gfp_mask; + unsigned int gfp_mask; struct radix_tree_node *rnode; }; @@ -50,7 +50,7 @@ void *radix_tree_delete(struct radix_tree_root *, unsigned long); unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items); -int radix_tree_preload(int gfp_mask); +int radix_tree_preload(unsigned int __nocast gfp_mask); void radix_tree_init(void); void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, int tag); diff --git a/lib/radix-tree.c b/lib/radix-tree.c index b972dd29289d6..6a8bc6e06431e 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -110,7 +110,7 @@ radix_tree_node_free(struct radix_tree_node *node) * success, return zero, with preemption disabled. On error, return -ENOMEM * with preemption not disabled. */ -int radix_tree_preload(int gfp_mask) +int radix_tree_preload(unsigned int __nocast gfp_mask) { struct radix_tree_preload *rtp; struct radix_tree_node *node; -- GitLab From 3a11ec5e502cb61ee31095008318f9c107d9db60 Mon Sep 17 00:00:00 2001 From: Victor Fusco <victor@cetuc.puc-rio.br> Date: Sat, 10 Sep 2005 00:26:49 -0700 Subject: [PATCH 379/563] [PATCH] dmapool: Fix "nocast type" warnings Fix the sparse warning "implicit cast to nocast type" Signed-off-by: Victor Fusco <victor@cetuc.puc-rio.br> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/base/dmapool.c | 3 ++- include/linux/dmapool.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index c4aebf2f522d7..60a7ef6a201b8 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c @@ -262,7 +262,8 @@ dma_pool_destroy (struct dma_pool *pool) * If such a memory block can't be allocated, null is returned. */ void * -dma_pool_alloc (struct dma_pool *pool, int mem_flags, dma_addr_t *handle) +dma_pool_alloc (struct dma_pool *pool, unsigned int __nocast mem_flags, + dma_addr_t *handle) { unsigned long flags; struct dma_page *page; diff --git a/include/linux/dmapool.h b/include/linux/dmapool.h index e60bfdac348d2..4932ee5c77f08 100644 --- a/include/linux/dmapool.h +++ b/include/linux/dmapool.h @@ -19,7 +19,8 @@ struct dma_pool *dma_pool_create(const char *name, struct device *dev, void dma_pool_destroy(struct dma_pool *pool); -void *dma_pool_alloc(struct dma_pool *pool, int mem_flags, dma_addr_t *handle); +void *dma_pool_alloc(struct dma_pool *pool, unsigned int __nocast mem_flags, + dma_addr_t *handle); void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr); -- GitLab From f4c9925ccc185da68c2d42230711d017f222e420 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:26:50 -0700 Subject: [PATCH 380/563] [PATCH] telephony/ixj: use msleep() instead of schedule_timeout() Replace schedule_timeout() with msleep() to guarantee the task delays as expected. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/telephony/ixj.c | 62 +++++++---------------------------------- 1 file changed, 10 insertions(+), 52 deletions(-) diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index f2c9fa423d402..9585d48dc4fc3 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -774,10 +774,7 @@ static int ixj_wink(IXJ *j) j->pots_winkstart = jiffies; SLIC_SetState(PLD_SLIC_STATE_OC, j); - while (time_before(jiffies, j->pots_winkstart + j->winktime)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + msleep(jiffies_to_msecs(j->winktime)); SLIC_SetState(slicnow, j); return 0; @@ -1912,7 +1909,6 @@ static int ixj_pcmcia_cable_check(IXJ *j) static int ixj_hookstate(IXJ *j) { - unsigned long det; int fOffHook = 0; switch (j->cardtype) { @@ -1943,11 +1939,7 @@ static int ixj_hookstate(IXJ *j) j->pld_slicr.bits.state == PLD_SLIC_STATE_STANDBY) { if (j->flags.ringing || j->flags.cringing) { if (!in_interrupt()) { - det = jiffies + (hertz / 50); - while (time_before(jiffies, det)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + msleep(20); } SLIC_GetState(j); if (j->pld_slicr.bits.state == PLD_SLIC_STATE_RINGING) { @@ -2062,7 +2054,7 @@ static void ixj_ring_start(IXJ *j) static int ixj_ring(IXJ *j) { char cntr; - unsigned long jif, det; + unsigned long jif; j->flags.ringing = 1; if (ixj_hookstate(j) & 1) { @@ -2070,7 +2062,6 @@ static int ixj_ring(IXJ *j) j->flags.ringing = 0; return 1; } - det = 0; for (cntr = 0; cntr < j->maxrings; cntr++) { jif = jiffies + (1 * hertz); ixj_ring_on(j); @@ -2089,13 +2080,7 @@ static int ixj_ring(IXJ *j) ixj_ring_off(j); while (time_before(jiffies, jif)) { if (ixj_hookstate(j) & 1) { - det = jiffies + (hertz / 100); - while (time_before(jiffies, det)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - if (signal_pending(current)) - break; - } + msleep(10); if (ixj_hookstate(j) & 1) { j->flags.ringing = 0; return 1; @@ -6694,8 +6679,6 @@ static struct file_operations ixj_fops = static int ixj_linetest(IXJ *j) { - unsigned long jifwait; - j->flags.pstncheck = 1; /* Testing */ j->flags.pstn_present = 0; /* Assume the line is not there */ @@ -6726,11 +6709,7 @@ static int ixj_linetest(IXJ *j) outb_p(j->pld_scrw.byte, j->XILINXbase); daa_set_mode(j, SOP_PU_CONVERSATION); - jifwait = jiffies + hertz; - while (time_before(jiffies, jifwait)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + msleep(1000); daa_int_read(j); daa_set_mode(j, SOP_PU_RESET); if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) { @@ -6750,11 +6729,7 @@ static int ixj_linetest(IXJ *j) j->pld_slicw.bits.rly3 = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); daa_set_mode(j, SOP_PU_CONVERSATION); - jifwait = jiffies + hertz; - while (time_before(jiffies, jifwait)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + msleep(1000); daa_int_read(j); daa_set_mode(j, SOP_PU_RESET); if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) { @@ -6783,7 +6758,6 @@ static int ixj_linetest(IXJ *j) static int ixj_selfprobe(IXJ *j) { unsigned short cmd; - unsigned long jif; int cnt; BYTES bytes; @@ -6933,29 +6907,13 @@ static int ixj_selfprobe(IXJ *j) } else { if (j->cardtype == QTI_LINEJACK) { LED_SetState(0x1, j); - jif = jiffies + (hertz / 10); - while (time_before(jiffies, jif)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + msleep(100); LED_SetState(0x2, j); - jif = jiffies + (hertz / 10); - while (time_before(jiffies, jif)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + msleep(100); LED_SetState(0x4, j); - jif = jiffies + (hertz / 10); - while (time_before(jiffies, jif)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + msleep(100); LED_SetState(0x8, j); - jif = jiffies + (hertz / 10); - while (time_before(jiffies, jif)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + msleep(100); LED_SetState(0x0, j); daa_get_version(j); if (ixjdebug & 0x0002) -- GitLab From aeb8397b6a289a358f04fa12b69194af6c259ad6 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:26:50 -0700 Subject: [PATCH 381/563] [PATCH] i386/smpboot: use msleep() instead of schedule_timeout() Replace schedule_timeout() with msleep() to guarantee the task delays as expected. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/kernel/smpboot.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 5e4893d2b9f27..c70cd2a083045 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -1330,8 +1330,7 @@ void __cpu_die(unsigned int cpu) printk ("CPU %d is now offline\n", cpu); return; } - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/10); + msleep(100); } printk(KERN_ERR "CPU %u didn't die...\n", cpu); } -- GitLab From b3358a116c25267446a45e4164cb2b8e98276da0 Mon Sep 17 00:00:00 2001 From: Pekka J Enberg <penberg@cs.Helsinki.FI> Date: Sat, 10 Sep 2005 00:26:51 -0700 Subject: [PATCH 382/563] [PATCH] update FSF address in COPYING FSF has moved so update the address as per http://www.gnu.org/licenses/gpl.txt. Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- COPYING | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/COPYING b/COPYING index 2a7e338ec2fc6..ca442d313d86d 100644 --- a/COPYING +++ b/COPYING @@ -18,7 +18,7 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -321,7 +321,7 @@ the "copyright" line and a pointer to where the full notice is found. 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 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. -- GitLab From 887c27f369abc458556a5ce8ab22ddd498474307 Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:26:52 -0700 Subject: [PATCH 383/563] [PATCH] fix unusual placement of inline keyword in hpet With gcc -W: drivers/char/hpet.c:102: warning: `inline' is not at beginning of declaration drivers/char/hpet.c:109: warning: `inline' is not at beginning of declaration Signed-off-by: Jesper Juhl <juhl-lkml@dif.dk> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/hpet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5fe8461271fc3..de0379b6d502c 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -100,14 +100,14 @@ static struct hpets *hpets; #endif #ifndef readq -static unsigned long long __inline readq(void __iomem *addr) +static inline unsigned long long readq(void __iomem *addr) { return readl(addr) | (((unsigned long long)readl(addr + 4)) << 32LL); } #endif #ifndef writeq -static void __inline writeq(unsigned long long v, void __iomem *addr) +static inline void writeq(unsigned long long v, void __iomem *addr) { writel(v & 0xffffffff, addr); writel(v >> 32, addr + 4); -- GitLab From f9101210e7aa72daf92722d451a2f7e3af5f781f Mon Sep 17 00:00:00 2001 From: Jesper Juhl <jesper.juhl@gmail.com> Date: Sat, 10 Sep 2005 00:26:54 -0700 Subject: [PATCH 384/563] [PATCH] vfree and kfree cleanup in drivers/ This patch does a full cleanup of 'NULL checks before vfree', and a partial cleanup of calls to kfree for all of drivers/ - the kfree bit is partial in that I only did the files that also had vfree calls in them. The patch also gets rid of some redundant (void *) casts of pointers being passed to [vk]free, and a some tiny whitespace corrections also crept in. Signed-off-by: Jesper Juhl <jesper.juhl@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/block/z2ram.c | 2 +- drivers/cdrom/sbpcd.c | 6 ++++-- drivers/char/agp/backend.c | 7 +++---- drivers/isdn/i4l/isdn_bsdcomp.c | 14 +++++-------- drivers/isdn/i4l/isdn_common.c | 3 ++- drivers/md/dm-exception-store.c | 9 +++----- drivers/media/common/saa7146_core.c | 6 ++---- drivers/media/video/cpia_usb.c | 30 +++++++++------------------ drivers/media/video/stradis.c | 32 +++++++++-------------------- drivers/media/video/video-buf.c | 8 ++++---- drivers/media/video/zoran_driver.c | 2 +- drivers/media/video/zr36120.c | 6 ++---- drivers/mtd/devices/mtdram.c | 3 +-- drivers/mtd/ftl.c | 11 ---------- drivers/net/bsd_comp.c | 28 ++++++++++--------------- drivers/scsi/53c7xx.c | 4 ++-- drivers/scsi/cpqfcTSinit.c | 3 +-- drivers/scsi/osst.c | 13 ++++++------ drivers/usb/media/stv680.c | 26 +++++++++++------------ drivers/video/vgastate.c | 15 +++++--------- 20 files changed, 86 insertions(+), 142 deletions(-) diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 007f6a6624392..bb5e8d665a2a3 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -296,7 +296,7 @@ z2_open( struct inode *inode, struct file *filp ) return 0; err_out_kfree: - kfree( z2ram_map ); + kfree(z2ram_map); err_out: return rc; } diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index 30a8977553617..0b7d7412c4a5f 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -4216,7 +4216,8 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd, case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */ msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n"); - if (current_drive->sbp_audsiz>0) vfree(current_drive->aud_buf); + if (current_drive->sbp_audsiz>0) + vfree(current_drive->aud_buf); current_drive->aud_buf=NULL; current_drive->sbp_audsiz=arg; @@ -5910,7 +5911,8 @@ static void sbpcd_exit(void) put_disk(D_S[j].disk); devfs_remove("sbp/c0t%d", j); vfree(D_S[j].sbp_buf); - if (D_S[j].sbp_audsiz>0) vfree(D_S[j].aud_buf); + if (D_S[j].sbp_audsiz>0) + vfree(D_S[j].aud_buf); if ((unregister_cdrom(D_S[j].sbpcd_infop) == -EINVAL)) { msg(DBG_INF, "What's that: can't unregister info %s.\n", major_name); diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 4d4e602fdc7e7..82b43c541c8dc 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -206,10 +206,9 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) bridge->driver->cleanup(); if (bridge->driver->free_gatt_table) bridge->driver->free_gatt_table(bridge); - if (bridge->key_list) { - vfree(bridge->key_list); - bridge->key_list = NULL; - } + + vfree(bridge->key_list); + bridge->key_list = NULL; if (bridge->driver->agp_destroy_page && bridge->driver->needs_scratch_page) diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index baf4bcad9bf93..0afe442db3b00 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -283,23 +283,19 @@ static void bsd_free (void *state) /* * Release the dictionary */ - if (db->dict) { - vfree (db->dict); - db->dict = NULL; - } + vfree(db->dict); + db->dict = NULL; /* * Release the string buffer */ - if (db->lens) { - vfree (db->lens); - db->lens = NULL; - } + vfree(db->lens); + db->lens = NULL; /* * Finally release the structure itself. */ - kfree (db); + kfree(db); } } diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index eebcb0b97f0e9..8a7d54a5c97d6 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1953,7 +1953,8 @@ isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding) kfree(d->rcvcount); if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_ATOMIC))) { printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); - if (!adding) kfree(d->rcverr); + if (!adding) + kfree(d->rcverr); return -1; } memset((char *) d->rcvcount, 0, sizeof(int) * m); diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index 17212b4201a15..cc07bbebbb168 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c @@ -568,12 +568,9 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size) bad: dm_io_put(sectors_to_pages(chunk_size)); - if (ps) { - if (ps->area) - free_area(ps); - - kfree(ps); - } + if (ps && ps->area) + free_area(ps); + kfree(ps); return r; } diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index cd5828b5e9e34..206cc2f61f261 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -168,10 +168,8 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) return; pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); pt->cpu = NULL; - if (NULL != pt->slist) { - kfree(pt->slist); - pt->slist = NULL; - } + kfree(pt->slist); + pt->slist = NULL; } int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c index cdda423386c5c..9774e94d1e7d9 100644 --- a/drivers/media/video/cpia_usb.c +++ b/drivers/media/video/cpia_usb.c @@ -445,10 +445,8 @@ static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try) ucpia->sbuf[1].urb = NULL; } - if (ucpia->sbuf[1].data) { - kfree(ucpia->sbuf[1].data); - ucpia->sbuf[1].data = NULL; - } + kfree(ucpia->sbuf[1].data); + ucpia->sbuf[1].data = NULL; if (ucpia->sbuf[0].urb) { usb_kill_urb(ucpia->sbuf[0].urb); @@ -456,10 +454,8 @@ static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try) ucpia->sbuf[0].urb = NULL; } - if (ucpia->sbuf[0].data) { - kfree(ucpia->sbuf[0].data); - ucpia->sbuf[0].data = NULL; - } + kfree(ucpia->sbuf[0].data); + ucpia->sbuf[0].data = NULL; } static int cpia_usb_close(void *privdata) @@ -623,20 +619,14 @@ static void cpia_disconnect(struct usb_interface *intf) ucpia->curbuff = ucpia->workbuff = NULL; - if (ucpia->buffers[2]) { - vfree(ucpia->buffers[2]); - ucpia->buffers[2] = NULL; - } + vfree(ucpia->buffers[2]); + ucpia->buffers[2] = NULL; - if (ucpia->buffers[1]) { - vfree(ucpia->buffers[1]); - ucpia->buffers[1] = NULL; - } + vfree(ucpia->buffers[1]); + ucpia->buffers[1] = NULL; - if (ucpia->buffers[0]) { - vfree(ucpia->buffers[0]); - ucpia->buffers[0] = NULL; - } + vfree(ucpia->buffers[0]); + ucpia->buffers[0] = NULL; cam->lowlevel_data = NULL; kfree(ucpia); diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index b57743571087b..d4497dbae05c7 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c @@ -2184,30 +2184,18 @@ static void release_saa(void) vfree(saa->vidbuf); vfree(saa->audbuf); vfree(saa->osdbuf); - if (saa->dmavid2) - kfree((void *) saa->dmavid2); + kfree(saa->dmavid2); saa->audbuf = saa->vidbuf = saa->osdbuf = NULL; saa->dmavid2 = NULL; - if (saa->dmadebi) - kfree((void *) saa->dmadebi); - if (saa->dmavid1) - kfree((void *) saa->dmavid1); - if (saa->dmavid2) - kfree((void *) saa->dmavid2); - if (saa->dmavid3) - kfree((void *) saa->dmavid3); - if (saa->dmaa1in) - kfree((void *) saa->dmaa1in); - if (saa->dmaa1out) - kfree((void *) saa->dmaa1out); - if (saa->dmaa2in) - kfree((void *) saa->dmaa2in); - if (saa->dmaa2out) - kfree((void *) saa->dmaa2out); - if (saa->dmaRPS1) - kfree((void *) saa->dmaRPS1); - if (saa->dmaRPS2) - kfree((void *) saa->dmaRPS2); + kfree(saa->dmadebi); + kfree(saa->dmavid1); + kfree(saa->dmavid3); + kfree(saa->dmaa1in); + kfree(saa->dmaa1out); + kfree(saa->dmaa2in); + kfree(saa->dmaa2out); + kfree(saa->dmaRPS1); + kfree(saa->dmaRPS2); free_irq(saa->irq, saa); if (saa->saa7146_mem) iounmap(saa->saa7146_mem); diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index 97354f253a802..574b8e36f3c61 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -267,10 +267,10 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) kfree(dma->pages); dma->pages = NULL; } - if (dma->vmalloc) { - vfree(dma->vmalloc); - dma->vmalloc = NULL; - } + + vfree(dma->vmalloc); + dma->vmalloc = NULL; + if (dma->bus_addr) { dma->bus_addr = 0; } diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index ba838a42ec806..53adeb70f2caf 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -650,7 +650,7 @@ jpg_fbuffer_free (struct file *file) off += PAGE_SIZE) ClearPageReserved(MAP_NR (mem + off)); - kfree((void *) mem); + kfree(mem); fh->jpg_buffers.buffer[i].frag_tab[0] = 0; fh->jpg_buffers.buffer[i].frag_tab[1] = 0; } diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c index c33533155cc72..07286816d7dfd 100644 --- a/drivers/media/video/zr36120.c +++ b/drivers/media/video/zr36120.c @@ -820,11 +820,9 @@ void zoran_close(struct video_device* dev) msleep(100); /* Wait 1/10th of a second */ /* free the allocated framebuffer */ - if (ztv->fbuffer) - bfree( ztv->fbuffer, ZORAN_MAX_FBUFSIZE ); + bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE); ztv->fbuffer = 0; - if (ztv->overinfo.overlay) - kfree( ztv->overinfo.overlay ); + kfree(ztv->overinfo.overlay); ztv->overinfo.overlay = 0; } diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index bb713fed2f373..1443117fd8f4a 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -91,8 +91,7 @@ static void __exit cleanup_mtdram(void) { if (mtd_info) { del_mtd_device(mtd_info); - if (mtd_info->priv) - vfree(mtd_info->priv); + vfree(mtd_info->priv); kfree(mtd_info); } } diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index d9ab60b36fd43..d32c1b3a8ce34 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1017,27 +1017,16 @@ static int ftl_writesect(struct mtd_blktrans_dev *dev, void ftl_freepart(partition_t *part) { - if (part->VirtualBlockMap) { vfree(part->VirtualBlockMap); part->VirtualBlockMap = NULL; - } - if (part->VirtualPageMap) { kfree(part->VirtualPageMap); part->VirtualPageMap = NULL; - } - if (part->EUNInfo) { kfree(part->EUNInfo); part->EUNInfo = NULL; - } - if (part->XferInfo) { kfree(part->XferInfo); part->XferInfo = NULL; - } - if (part->bam_cache) { kfree(part->bam_cache); part->bam_cache = NULL; - } - } /* ftl_freepart */ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c index 3d88ad622bdb3..fb4098ed469ee 100644 --- a/drivers/net/bsd_comp.c +++ b/drivers/net/bsd_comp.c @@ -323,33 +323,27 @@ static void bsd_reset (void *state) */ static void bsd_free (void *state) - { - struct bsd_db *db = (struct bsd_db *) state; +{ + struct bsd_db *db = state; - if (db) - { + if (!db) + return; + /* * Release the dictionary */ - if (db->dict) - { - vfree (db->dict); - db->dict = NULL; - } + vfree(db->dict); + db->dict = NULL; /* * Release the string buffer */ - if (db->lens) - { - vfree (db->lens); - db->lens = NULL; - } + vfree(db->lens); + db->lens = NULL; /* * Finally release the structure itself. */ - kfree (db); - } - } + kfree(db); +} /* * Allocate space for a (de) compressor. diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c index 2341d27ceed73..7a33c708f5b3d 100644 --- a/drivers/scsi/53c7xx.c +++ b/drivers/scsi/53c7xx.c @@ -6090,8 +6090,8 @@ NCR53c7x0_release(struct Scsi_Host *host) { if (hostdata->num_cmds) printk ("scsi%d : leaked %d NCR53c7x0_cmd structures\n", host->host_no, hostdata->num_cmds); - if (hostdata->events) - vfree ((void *)hostdata->events); + + vfree(hostdata->events); /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which * XXX may be invalid (CONFIG_060_WRITETHROUGH) diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c index d72be0ce89c84..3fda8d455c5b0 100644 --- a/drivers/scsi/cpqfcTSinit.c +++ b/drivers/scsi/cpqfcTSinit.c @@ -691,8 +691,7 @@ int cpqfcTS_ioctl( struct scsi_device *ScsiDev, int Cmnd, void *arg) if( copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len)) result = -EFAULT; - if( buf) - kfree( buf); + kfree(buf); return result; } diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 89a4a0615c22d..3f2f2464fa635 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -1377,7 +1377,7 @@ static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct scsi if ((STp->buffer)->syscall_result || !SRpnt) { printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name); - vfree((void *)buffer); + vfree(buffer); *aSRpnt = SRpnt; return (-EIO); } @@ -1419,7 +1419,7 @@ static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct scsi if (new_frame > frame + 1000) { printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name); - vfree((void *)buffer); + vfree(buffer); return (-EIO); } if ( i >= nframes + pending ) break; @@ -1500,7 +1500,7 @@ static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct scsi SRpnt->sr_sense_buffer[12] == 0 && SRpnt->sr_sense_buffer[13] == 2) { printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name); - vfree((void *)buffer); + vfree(buffer); return (-EIO); /* hit end of tape = fail */ } i = ((SRpnt->sr_sense_buffer[3] << 24) | @@ -1525,7 +1525,7 @@ static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct scsi } if (!pending) osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */ - vfree((void *)buffer); + vfree(buffer); return 0; } @@ -5852,7 +5852,7 @@ static int osst_remove(struct device *dev) os_scsi_tapes[i] = NULL; osst_nr_dev--; write_unlock(&os_scsi_tapes_lock); - if (tpnt->header_cache != NULL) vfree(tpnt->header_cache); + vfree(tpnt->header_cache); if (tpnt->buffer) { normalize_buffer(tpnt->buffer); kfree(tpnt->buffer); @@ -5896,8 +5896,7 @@ static void __exit exit_osst (void) for (i=0; i < osst_max_dev; ++i) { if (!(STp = os_scsi_tapes[i])) continue; /* This is defensive, supposed to happen during detach */ - if (STp->header_cache) - vfree(STp->header_cache); + vfree(STp->header_cache); if (STp->buffer) { normalize_buffer(STp->buffer); kfree(STp->buffer); diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c index 7398a7f19c1e4..0fd0fa9fec21f 100644 --- a/drivers/usb/media/stv680.c +++ b/drivers/usb/media/stv680.c @@ -260,7 +260,7 @@ static int stv_stop_video (struct usb_stv *dev) PDEBUG (0, "STV(i): Camera set to original resolution"); } /* origMode */ - kfree (buf); + kfree(buf); return i; } @@ -276,7 +276,7 @@ static int stv_set_video_mode (struct usb_stv *dev) } if ((i = stv_set_config (dev, 1, 0, 0)) < 0) { - kfree (buf); + kfree(buf); return i; } @@ -301,13 +301,13 @@ static int stv_set_video_mode (struct usb_stv *dev) goto exit; error: - kfree (buf); + kfree(buf); if (stop_video == 1) stv_stop_video (dev); return -1; exit: - kfree (buf); + kfree(buf); return 0; } @@ -327,7 +327,7 @@ static int stv_init (struct usb_stv *stv680) /* set config 1, interface 0, alternate 0 */ if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) { - kfree (buffer); + kfree(buffer); PDEBUG (0, "STV(e): set config 1,0,0 failed"); return -1; } @@ -435,11 +435,11 @@ static int stv_init (struct usb_stv *stv680) error: i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02); /* Get Last Error */ PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buffer[0], buffer[1]); - kfree (buffer); + kfree(buffer); return -1; exit: - kfree (buffer); + kfree(buffer); /* video = 320x240, 352x288 */ if (stv680->CIF == 1) { @@ -708,10 +708,10 @@ static int stv680_stop_stream (struct usb_stv *stv680) usb_kill_urb (stv680->urb[i]); usb_free_urb (stv680->urb[i]); stv680->urb[i] = NULL; - kfree (stv680->sbuf[i].data); + kfree(stv680->sbuf[i].data); } for (i = 0; i < STV680_NUMSCRATCH; i++) { - kfree (stv680->scratch[i].data); + kfree(stv680->scratch[i].data); stv680->scratch[i].data = NULL; } @@ -1068,7 +1068,7 @@ static int stv_close (struct inode *inode, struct file *file) stv680->user = 0; if (stv680->removed) { - kfree (stv680); + kfree(stv680); stv680 = NULL; PDEBUG (0, "STV(i): device unregistered"); } @@ -1445,14 +1445,14 @@ static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680) usb_kill_urb (stv680->urb[i]); usb_free_urb (stv680->urb[i]); stv680->urb[i] = NULL; - kfree (stv680->sbuf[i].data); + kfree(stv680->sbuf[i].data); } for (i = 0; i < STV680_NUMSCRATCH; i++) - kfree (stv680->scratch[i].data); + kfree(stv680->scratch[i].data); PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name); /* Free the memory */ - kfree (stv680); + kfree(stv680); } static void stv680_disconnect (struct usb_interface *intf) diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c index 0ea62d8bc703d..ca92940f39438 100644 --- a/drivers/video/vgastate.c +++ b/drivers/video/vgastate.c @@ -342,16 +342,11 @@ static void vga_cleanup(struct vgastate *state) if (state->vidstate != NULL) { struct regstate *saved = (struct regstate *) state->vidstate; - if (saved->vga_font0) - vfree(saved->vga_font0); - if (saved->vga_font1) - vfree(saved->vga_font1); - if (saved->vga_text) - vfree(saved->vga_text); - if (saved->vga_cmap) - vfree(saved->vga_cmap); - if (saved->attr) - vfree(saved->attr); + vfree(saved->vga_font0); + vfree(saved->vga_font1); + vfree(saved->vga_text); + vfree(saved->vga_cmap); + vfree(saved->attr); kfree(saved); state->vidstate = NULL; } -- GitLab From 338cec3253a6d43d02e5e96abc327197565efcc8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:26:54 -0700 Subject: [PATCH 385/563] [PATCH] merge some from Rusty's trivial patches This patch contains the most trivial from Rusty's trivial patches: - spelling fixes - remove duplicate includes Signed-off-by: Adrian Bunk <bunk@stusta.de> Cc: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/mono.txt | 2 +- Documentation/pci.txt | 2 +- Documentation/sysrq.txt | 2 +- arch/ppc/kernel/cpu_setup_6xx.S | 1 - arch/ppc/kernel/cpu_setup_power4.S | 1 - arch/ppc/kernel/dma-mapping.c | 2 +- arch/ppc64/kernel/cpu_setup_power4.S | 1 - drivers/ide/ide-io.c | 6 +++--- drivers/md/md.c | 4 ++-- drivers/parisc/lasi.c | 1 - drivers/scsi/ibmmca.c | 1 - ipc/mqueue.c | 2 +- 12 files changed, 10 insertions(+), 15 deletions(-) diff --git a/Documentation/mono.txt b/Documentation/mono.txt index 6739ab9615ef7..807a0c7b4737c 100644 --- a/Documentation/mono.txt +++ b/Documentation/mono.txt @@ -30,7 +30,7 @@ other program after you have done the following: Read the file 'binfmt_misc.txt' in this directory to know more about the configuration process. -3) Add the following enries to /etc/rc.local or similar script +3) Add the following entries to /etc/rc.local or similar script to be run at system startup: # Insert BINFMT_MISC module into the kernel diff --git a/Documentation/pci.txt b/Documentation/pci.txt index 76d28d033657a..711210b38f5fe 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt @@ -84,7 +84,7 @@ Each entry consists of: Most drivers don't need to use the driver_data field. Best practice for use of driver_data is to use it as an index into a static list of -equivalant device types, not to use it as a pointer. +equivalent device types, not to use it as a pointer. Have a table entry {PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID} to have probe() called for every PCI device known to the system. diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt index 136d817c01bab..baf17b381588d 100644 --- a/Documentation/sysrq.txt +++ b/Documentation/sysrq.txt @@ -171,7 +171,7 @@ the header 'include/linux/sysrq.h', this will define everything else you need. Next, you must create a sysrq_key_op struct, and populate it with A) the key handler function you will use, B) a help_msg string, that will print when SysRQ prints help, and C) an action_msg string, that will print right before your -handler is called. Your handler must conform to the protoype in 'sysrq.h'. +handler is called. Your handler must conform to the prototype in 'sysrq.h'. After the sysrq_key_op is created, you can call the macro register_sysrq_key(int key, struct sysrq_key_op *op_p) that is defined in diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S index 1f37b7eafac21..ba396438ede34 100644 --- a/arch/ppc/kernel/cpu_setup_6xx.S +++ b/arch/ppc/kernel/cpu_setup_6xx.S @@ -12,7 +12,6 @@ #include <linux/config.h> #include <asm/processor.h> #include <asm/page.h> -#include <asm/ppc_asm.h> #include <asm/cputable.h> #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> diff --git a/arch/ppc/kernel/cpu_setup_power4.S b/arch/ppc/kernel/cpu_setup_power4.S index 304589aebdbcc..7e4fbb6537240 100644 --- a/arch/ppc/kernel/cpu_setup_power4.S +++ b/arch/ppc/kernel/cpu_setup_power4.S @@ -14,7 +14,6 @@ #include <asm/page.h> #include <asm/ppc_asm.h> #include <asm/cputable.h> -#include <asm/ppc_asm.h> #include <asm/asm-offsets.h> #include <asm/cache.h> diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/ppc/kernel/dma-mapping.c index e0c631cf96b03..b566d982806c9 100644 --- a/arch/ppc/kernel/dma-mapping.c +++ b/arch/ppc/kernel/dma-mapping.c @@ -393,7 +393,7 @@ EXPORT_SYMBOL(__dma_sync); * __dma_sync_page() implementation for systems using highmem. * In this case, each page of a buffer must be kmapped/kunmapped * in order to have a virtual address for __dma_sync(). This must - * not sleep so kmap_atmomic()/kunmap_atomic() are used. + * not sleep so kmap_atomic()/kunmap_atomic() are used. * * Note: yes, it is possible and correct to have a buffer extend * beyond the first page. diff --git a/arch/ppc64/kernel/cpu_setup_power4.S b/arch/ppc64/kernel/cpu_setup_power4.S index bfce609e8e6be..1fb673c511ff5 100644 --- a/arch/ppc64/kernel/cpu_setup_power4.S +++ b/arch/ppc64/kernel/cpu_setup_power4.S @@ -12,7 +12,6 @@ #include <linux/config.h> #include <asm/processor.h> #include <asm/page.h> -#include <asm/ppc_asm.h> #include <asm/cputable.h> #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index f174aee659e5e..9e9cf1407311f 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -560,7 +560,7 @@ ide_startstop_t __ide_abort(ide_drive_t *drive, struct request *rq) EXPORT_SYMBOL_GPL(__ide_abort); /** - * ide_abort - abort pending IDE operatins + * ide_abort - abort pending IDE operations * @drive: drive the error occurred on * @msg: message to report * @@ -623,7 +623,7 @@ static void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, * @drive: drive the completion interrupt occurred on * * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. - * We do any necessary daya reading and then wait for the drive to + * We do any necessary data reading and then wait for the drive to * go non busy. At that point we may read the error data and complete * the request */ @@ -773,7 +773,7 @@ EXPORT_SYMBOL_GPL(ide_init_sg_cmd); /** * execute_drive_command - issue special drive command - * @drive: the drive to issue th command on + * @drive: the drive to issue the command on * @rq: the request structure holding the command * * execute_drive_cmd() issues a special drive command, usually diff --git a/drivers/md/md.c b/drivers/md/md.c index 1554b924fbb9d..2897df90df448 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -74,7 +74,7 @@ static DEFINE_SPINLOCK(pers_lock); * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' * is 1000 KB/sec, so the extra system load does not show up that much. * Increase it if you want to have more _guaranteed_ speed. Note that - * the RAID driver will use the maximum available bandwith if the IO + * the RAID driver will use the maximum available bandwidth if the IO * subsystem is idle. There is also an 'absolute maximum' reconstruction * speed limit - in case reconstruction slows down your system despite * idle IO detection. @@ -3616,7 +3616,7 @@ static void md_do_sync(mddev_t *mddev) printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev)); printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" " %d KB/sec/disc.\n", sysctl_speed_limit_min); - printk(KERN_INFO "md: using maximum available idle IO bandwith " + printk(KERN_INFO "md: using maximum available idle IO bandwidth " "(but not more than %d KB/sec) for reconstruction.\n", sysctl_speed_limit_max); diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c index 7318550533929..cb84a4e84a2fd 100644 --- a/drivers/parisc/lasi.c +++ b/drivers/parisc/lasi.c @@ -20,7 +20,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/pm.h> -#include <linux/slab.h> #include <linux/types.h> #include <asm/io.h> diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index b5dc353555707..6e54c7d9b33c9 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -36,7 +36,6 @@ #include <linux/proc_fs.h> #include <linux/stat.h> #include <linux/mca.h> -#include <linux/string.h> #include <linux/spinlock.h> #include <linux/init.h> #include <linux/mca-legacy.h> diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 0acf245f441d6..3a926011507b8 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -69,7 +69,7 @@ struct mqueue_inode_info { struct sigevent notify; pid_t notify_owner; - struct user_struct *user; /* user who created, for accouting */ + struct user_struct *user; /* user who created, for accounting */ struct sock *notify_sock; struct sk_buff *notify_cookie; -- GitLab From f8e38dde33b839bb9e9f98e88688bfac1811d57a Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:26:55 -0700 Subject: [PATCH 386/563] [PATCH] include/asm-arm26/hardirq.h: remove #define irq_enter() This patch removes a #define for irq_enter that is superfluous due to a similar one in include/linux/hardirq.h. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-arm26/hardirq.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/asm-arm26/hardirq.h b/include/asm-arm26/hardirq.h index 791ee1da9bfa0..dc28daab8aa8d 100644 --- a/include/asm-arm26/hardirq.h +++ b/include/asm-arm26/hardirq.h @@ -22,8 +22,6 @@ typedef struct { # error HARDIRQ_BITS is too low! #endif -#define irq_enter() (preempt_count() += HARDIRQ_OFFSET) - #ifndef CONFIG_SMP extern asmlinkage void __do_softirq(void); -- GitLab From 82b44429e0c8a8fec8f36e98a725f516227dabc0 Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:26:56 -0700 Subject: [PATCH 387/563] [PATCH] patch] remove sound/oss/skeleton.c We do no longer need a template for OSS drivers. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- sound/oss/skeleton.c | 219 ------------------------------------------- 1 file changed, 219 deletions(-) delete mode 100644 sound/oss/skeleton.c diff --git a/sound/oss/skeleton.c b/sound/oss/skeleton.c deleted file mode 100644 index 8fea783dd0cba..0000000000000 --- a/sound/oss/skeleton.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * PCI sound skeleton example - * - * (c) 1998 Red Hat Software - * - * This software may be used and distributed according to the - * terms of the GNU General Public License, incorporated herein by - * reference. - * - * This example is designed to be built in the linux/drivers/sound - * directory as part of a kernel build. The example is modular only - * drop me a note once you have a working modular driver and want - * to integrate it with the main code. - * -- Alan <alan@redhat.com> - * - * This is a first draft. Please report any errors, corrections or - * improvements to me. - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/pci.h> - -#include <asm/io.h> - -#include "sound_config.h" - -/* - * Define our PCI vendor ID here - */ - -#ifndef PCI_VENDOR_MYIDENT -#define PCI_VENDOR_MYIDENT 0x125D - -/* - * PCI identity for the card. - */ - -#define PCI_DEVICE_ID_MYIDENT_MYCARD1 0x1969 -#endif - -#define CARD_NAME "ExampleWave 3D Pro Ultra ThingyWotsit" - -#define MAX_CARDS 8 - -/* - * Each address_info object holds the information about one of - * our card resources. In this case the MSS emulation of our - * ficticious card. Its used to manage and attach things. - */ - -static struct address_info mss_data[MAX_CARDS]; -static int cards; - -/* - * Install the actual card. This is an example - */ - -static int mycard_install(struct pci_dev *pcidev) -{ - int iobase; - int mssbase; - int mpubase; - u8 x; - u16 w; - u32 v; - int i; - int dma; - - /* - * Our imaginary code has its I/O on PCI address 0, a - * MSS on PCI address 1 and an MPU on address 2 - * - * For the example we will only initialise the MSS - */ - - iobase = pci_resource_start(pcidev, 0); - mssbase = pci_resource_start(pcidev, 1); - mpubase = pci_resource_start(pcidev, 2); - - /* - * Reset the board - */ - - /* - * Wait for completion. udelay() waits in microseconds - */ - - udelay(100); - - /* - * Ok card ready. Begin setup proper. You might for example - * load the firmware here - */ - - dma = card_specific_magic(ioaddr); - - /* - * Turn on legacy mode (example), There are also byte and - * dword (32bit) PCI configuration function calls - */ - - pci_read_config_word(pcidev, 0x40, &w); - w&=~(1<<15); /* legacy decode on */ - w|=(1<<14); /* Reserved write as 1 in this case */ - w|=(1<<3)|(1<<1)|(1<<0); /* SB on , FM on, MPU on */ - pci_write_config_word(pcidev, 0x40, w); - - /* - * Let the user know we found his toy. - */ - - printk(KERN_INFO "Programmed "CARD_NAME" at 0x%X to legacy mode.\n", - iobase); - - /* - * Now set it up the description of the card - */ - - mss_data[cards].io_base = mssbase; - mss_data[cards].irq = pcidev->irq; - mss_data[cards].dma = dma; - - /* - * Check there is an MSS present - */ - - if(ad1848_detect(mssbase, NULL, mss_data[cards].osp)==0) - return 0; - - /* - * Initialize it - */ - - mss_data[cards].slots[3] = ad1848_init("MyCard MSS 16bit", - mssbase, - mss_data[cards].irq, - mss_data[cards].dma, - mss_data[cards].dma, - 0, - 0, - THIS_MODULE); - - cards++; - return 1; -} - - -/* - * This loop walks the PCI configuration database and finds where - * the sound cards are. - */ - -int init_mycard(void) -{ - struct pci_dev *pcidev=NULL; - int count=0; - - while((pcidev = pci_find_device(PCI_VENDOR_MYIDENT, PCI_DEVICE_ID_MYIDENT_MYCARD1, pcidev))!=NULL) - { - if (pci_enable_device(pcidev)) - continue; - count+=mycard_install(pcidev); - if(count) - return 0; - if(count==MAX_CARDS) - break; - } - - if(count==0) - return -ENODEV; - return 0; -} - -/* - * This function is called when the user or kernel loads the - * module into memory. - */ - - -int init_module(void) -{ - if(init_mycard()<0) - { - printk(KERN_ERR "No "CARD_NAME" cards found.\n"); - return -ENODEV; - } - - return 0; -} - -/* - * This is called when it is removed. It will only be removed - * when its use count is 0. - */ - -void cleanup_module(void) -{ - for(i=0;i< cards; i++) - { - /* - * Free attached resources - */ - - ad1848_unload(mss_data[i].io_base, - mss_data[i].irq, - mss_data[i].dma, - mss_data[i].dma, - 0); - /* - * And disconnect the device from the kernel - */ - sound_unload_audiodevice(mss_data[i].slots[3]); - } -} - -- GitLab From 96757701336365e30bea9fccdfac087338954e09 Mon Sep 17 00:00:00 2001 From: Marcelo Feitoza Parisi <marcelo@feitoza.com.br> Date: Sat, 10 Sep 2005 00:26:57 -0700 Subject: [PATCH 388/563] [PATCH] drivers/char/lp.c : Use of the time_after() macro Use of the time_after() macro, defined at linux/jiffies.h, which deals with wrapping correctly and are nicer to read. Signed-off-by: Marcelo Feitoza Parisi <marcelo@feitoza.com.br> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/lp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 59eebe5a035f1..2afb9038dbc57 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -128,6 +128,7 @@ #include <linux/console.h> #include <linux/device.h> #include <linux/wait.h> +#include <linux/jiffies.h> #include <linux/parport.h> #undef LP_STATS @@ -307,7 +308,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf, (LP_F(minor) & LP_ABORT)); #ifdef LP_STATS - if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) + if (time_after(jiffies, lp_table[minor].lastcall + LP_TIME(minor))) lp_table[minor].runchars = 0; lp_table[minor].lastcall = jiffies; -- GitLab From 9dcbb32f1654e79c212c20d9cd9d48509ee1eaf7 Mon Sep 17 00:00:00 2001 From: Tobias Klauser <tklauser@nuerscht.ch> Date: Sat, 10 Sep 2005 00:26:58 -0700 Subject: [PATCH 389/563] [PATCH] Spelling and whitespace fixes for REPORTING-BUGS The attached patch fixes some spelling errors in REPORTING-BUGS and also removes all trailing whitespaces. Signed-off-by: Tobias Klauser <tklauser@nuerscht.ch> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- REPORTING-BUGS | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/REPORTING-BUGS b/REPORTING-BUGS index 224c34741d32d..f9da827a0c188 100644 --- a/REPORTING-BUGS +++ b/REPORTING-BUGS @@ -9,7 +9,7 @@ screen please read "Documentation/oops-tracing.txt" before posting your bug report. This explains what you should do with the "Oops" information to make it useful to the recipient. - Send the output the maintainer of the kernel area that seems to + Send the output to the maintainer of the kernel area that seems to be involved with the problem. Don't worry too much about getting the wrong person. If you are unsure send it to the person responsible for the code relevant to what you were doing. If it occurs repeatably try and @@ -18,15 +18,15 @@ The list of maintainers is in the MAINTAINERS file in this directory. If it is a security bug, please copy the Security Contact listed in the MAINTAINERS file. They can help coordinate bugfix and disclosure. -See Documentation/SecurityBugs for more infomation. +See Documentation/SecurityBugs for more information. If you are totally stumped as to whom to send the report, send it to linux-kernel@vger.kernel.org. (For more information on the linux-kernel mailing list see http://www.tux.org/lkml/). -This is a suggested format for a bug report sent to the Linux kernel mailing -list. Having a standardized bug report form makes it easier for you not to -overlook things, and easier for the developers to find the pieces of +This is a suggested format for a bug report sent to the Linux kernel mailing +list. Having a standardized bug report form makes it easier for you not to +overlook things, and easier for the developers to find the pieces of information they're really interested in. Don't feel you have to follow it. First run the ver_linux script included as scripts/ver_linux, which @@ -35,9 +35,9 @@ the command "sh scripts/ver_linux". Use that information to fill in all fields of the bug report form, and post it to the mailing list with a subject of "PROBLEM: <one line -summary from [1.]>" for easy identification by the developers +summary from [1.]>" for easy identification by the developers. -[1.] One line summary of the problem: +[1.] One line summary of the problem: [2.] Full description of the problem/report: [3.] Keywords (i.e., modules, networking, kernel): [4.] Kernel version (from /proc/version): -- GitLab From 207f36eec9e7b1077d7a0aaadb4800e2c9b4cfa4 Mon Sep 17 00:00:00 2001 From: Renaud Lienhart <renaud.lienhart@free.fr> Date: Sat, 10 Sep 2005 00:26:59 -0700 Subject: [PATCH 390/563] [PATCH] remove invalid comment in mm/page_alloc.c free_pages_bulk() doesn't free the entire list if count == 0. Signed-off-by: Renaud Lienhart <renaud.lienhart@free.fr> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- mm/page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 3974fd81d27c0..c5823c395f714 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -335,7 +335,7 @@ static inline void free_pages_check(const char *function, struct page *page) /* * Frees a list of pages. * Assumes all pages on list are in same zone, and of same order. - * count is the number of pages to free, or 0 for all on the list. + * count is the number of pages to free. * * If the zone was previously in an "all pages pinned" state then look to * see if this freeing clears that state. -- GitLab From ecec4cb7a9df5f61fe00710d2f2c69ce9a3b1d40 Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:26:59 -0700 Subject: [PATCH 391/563] [PATCH] lib/sort.c: small cleanups This patch contains the following small cleanups: - make two needlessly global functions static - every file should #include the header files containing the prototypes of it's global functions Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- lib/sort.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/sort.c b/lib/sort.c index b73dbb0e7c83a..ddc4d35df289c 100644 --- a/lib/sort.c +++ b/lib/sort.c @@ -6,15 +6,16 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/sort.h> -void u32_swap(void *a, void *b, int size) +static void u32_swap(void *a, void *b, int size) { u32 t = *(u32 *)a; *(u32 *)a = *(u32 *)b; *(u32 *)b = t; } -void generic_swap(void *a, void *b, int size) +static void generic_swap(void *a, void *b, int size) { char t; -- GitLab From 2665b891c42ef67eb4cb51d665b523892f992749 Mon Sep 17 00:00:00 2001 From: Clemens Buchacher <drizzd@aon.at> Date: Sat, 10 Sep 2005 00:27:00 -0700 Subject: [PATCH 392/563] [PATCH] janitor: ide: min/max macros in ide-timing.h I replaced the custom MIN/MAX macros with the type safe min/max macros from linux/kernel.h. Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Cc: Bartlomiej Zolnierkiewicz <B.Zolnierkiewicz@elka.pw.edu.pl> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/ide/ide-timing.h | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h index c1196ce15b4d4..2fcfac6e967aa 100644 --- a/drivers/ide/ide-timing.h +++ b/drivers/ide/ide-timing.h @@ -27,6 +27,7 @@ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ +#include <linux/kernel.h> #include <linux/hdreg.h> #define XFER_PIO_5 0x0d @@ -96,11 +97,9 @@ static struct ide_timing ide_timing[] = { #define IDE_TIMING_UDMA 0x80 #define IDE_TIMING_ALL 0xff -#define MIN(a,b) ((a)<(b)?(a):(b)) -#define MAX(a,b) ((a)>(b)?(a):(b)) -#define FIT(v,min,max) MAX(MIN(v,max),min) -#define ENOUGH(v,unit) (((v)-1)/(unit)+1) -#define EZ(v,unit) ((v)?ENOUGH(v,unit):0) +#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin) +#define ENOUGH(v,unit) (((v)-1)/(unit)+1) +#define EZ(v,unit) ((v)?ENOUGH(v,unit):0) #define XFER_MODE 0xf0 #define XFER_UDMA_133 0x48 @@ -188,14 +187,14 @@ static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int static void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, struct ide_timing *m, unsigned int what) { - if (what & IDE_TIMING_SETUP ) m->setup = MAX(a->setup, b->setup); - if (what & IDE_TIMING_ACT8B ) m->act8b = MAX(a->act8b, b->act8b); - if (what & IDE_TIMING_REC8B ) m->rec8b = MAX(a->rec8b, b->rec8b); - if (what & IDE_TIMING_CYC8B ) m->cyc8b = MAX(a->cyc8b, b->cyc8b); - if (what & IDE_TIMING_ACTIVE ) m->active = MAX(a->active, b->active); - if (what & IDE_TIMING_RECOVER) m->recover = MAX(a->recover, b->recover); - if (what & IDE_TIMING_CYCLE ) m->cycle = MAX(a->cycle, b->cycle); - if (what & IDE_TIMING_UDMA ) m->udma = MAX(a->udma, b->udma); + if (what & IDE_TIMING_SETUP ) m->setup = max(a->setup, b->setup); + if (what & IDE_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b); + if (what & IDE_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b); + if (what & IDE_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b); + if (what & IDE_TIMING_ACTIVE ) m->active = max(a->active, b->active); + if (what & IDE_TIMING_RECOVER) m->recover = max(a->recover, b->recover); + if (what & IDE_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle); + if (what & IDE_TIMING_UDMA ) m->udma = max(a->udma, b->udma); } static struct ide_timing* ide_timing_find_mode(short speed) -- GitLab From 81616c5a0811564667ef39928da4573d99c70bed Mon Sep 17 00:00:00 2001 From: Domen Puncer <domen@coderock.org> Date: Sat, 10 Sep 2005 00:27:04 -0700 Subject: [PATCH 393/563] [PATCH] janitor: net/ppp-generic: list_for_each_entry Make code more readable with list_for_each_entry. Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Cc: Paul Mackerras <paulus@samba.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/net/ppp_generic.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index bb71638a7c448..0df7e92b0bf8d 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1232,9 +1232,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) navail = 0; /* total # of usable channels (not deregistered) */ hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; i = 0; - list = &ppp->channels; - while ((list = list->next) != &ppp->channels) { - pch = list_entry(list, struct channel, clist); + list_for_each_entry(pch, &ppp->channels, clist) { navail += pch->avail = (pch->chan != NULL); if (pch->avail) { if (skb_queue_empty(&pch->file.xq) || @@ -1280,6 +1278,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) /* skip to the channel after the one we last used and start at that one */ + list = &ppp->channels; for (i = 0; i < ppp->nxchan; ++i) { list = list->next; if (list == &ppp->channels) { @@ -1730,7 +1729,7 @@ static void ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) { u32 mask, seq; - struct list_head *l; + struct channel *ch; int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0) @@ -1784,8 +1783,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) * The list of channels can't change because we have the receive * side of the ppp unit locked. */ - for (l = ppp->channels.next; l != &ppp->channels; l = l->next) { - struct channel *ch = list_entry(l, struct channel, clist); + list_for_each_entry(ch, &ppp->channels, clist) { if (seq_before(ch->lastseq, seq)) seq = ch->lastseq; } @@ -2271,10 +2269,8 @@ static struct compressor_entry * find_comp_entry(int proto) { struct compressor_entry *ce; - struct list_head *list = &compressor_list; - while ((list = list->next) != &compressor_list) { - ce = list_entry(list, struct compressor_entry, list); + list_for_each_entry(ce, &compressor_list, list) { if (ce->comp->compress_proto == proto) return ce; } @@ -2540,20 +2536,15 @@ static struct channel * ppp_find_channel(int unit) { struct channel *pch; - struct list_head *list; - list = &new_channels; - while ((list = list->next) != &new_channels) { - pch = list_entry(list, struct channel, list); + list_for_each_entry(pch, &new_channels, list) { if (pch->file.index == unit) { list_del(&pch->list); list_add(&pch->list, &all_channels); return pch; } } - list = &all_channels; - while ((list = list->next) != &all_channels) { - pch = list_entry(list, struct channel, list); + list_for_each_entry(pch, &all_channels, list) { if (pch->file.index == unit) return pch; } -- GitLab From 216d81bb35fc50923993462cc4fbc7029f9be1a9 Mon Sep 17 00:00:00 2001 From: Domen Puncer <domen@coderock.org> Date: Sat, 10 Sep 2005 00:27:05 -0700 Subject: [PATCH 394/563] [PATCH] janitor: jffs/intrep: list_for_each_entry Use list_for_each_entry to make code more readable. Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Cc: <jffs-dev@axis.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/jffs/intrep.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c index 456d7e6e29c26..27f199e94cfc8 100644 --- a/fs/jffs/intrep.c +++ b/fs/jffs/intrep.c @@ -1701,12 +1701,10 @@ jffs_find_file(struct jffs_control *c, __u32 ino) { struct jffs_file *f; int i = ino % c->hash_len; - struct list_head *tmp; D3(printk("jffs_find_file(): ino: %u\n", ino)); - for (tmp = c->hash[i].next; tmp != &c->hash[i]; tmp = tmp->next) { - f = list_entry(tmp, struct jffs_file, hash); + list_for_each_entry(f, &c->hash[i], hash) { if (ino != f->ino) continue; D3(printk("jffs_find_file(): Found file with ino " @@ -2102,13 +2100,12 @@ jffs_foreach_file(struct jffs_control *c, int (*func)(struct jffs_file *)) int result = 0; for (pos = 0; pos < c->hash_len; pos++) { - struct list_head *p, *next; - for (p = c->hash[pos].next; p != &c->hash[pos]; p = next) { - /* We need a reference to the next file in the - list because `func' might remove the current - file `f'. */ - next = p->next; - r = func(list_entry(p, struct jffs_file, hash)); + struct jffs_file *f, *next; + + /* We must do _safe, because 'func' might remove the + current file 'f' from the list. */ + list_for_each_entry_safe(f, next, &c->hash[pos], hash) { + r = func(f); if (r < 0) return r; result += r; @@ -2613,9 +2610,8 @@ jffs_print_hash_table(struct jffs_control *c) printk("JFFS: Dumping the file system's hash table...\n"); for (i = 0; i < c->hash_len; i++) { - struct list_head *p; - for (p = c->hash[i].next; p != &c->hash[i]; p = p->next) { - struct jffs_file *f=list_entry(p,struct jffs_file,hash); + struct jffs_file *f; + list_for_each_entry(f, &c->hash[i], hash) { printk("*** c->hash[%u]: \"%s\" " "(ino: %u, pino: %u)\n", i, (f->name ? f->name : ""), -- GitLab From fdadd65fbce0ff966cb8e74247d9636f52a7fc7a Mon Sep 17 00:00:00 2001 From: Domen Puncer <domen@coderock.org> Date: Sat, 10 Sep 2005 00:27:07 -0700 Subject: [PATCH 395/563] [PATCH] janitor: fs/namespace.c: list_for_each_entry Make code more readable with list_for_each_entry. Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/namespace.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 34156260c9b65..2fa9fdf7d6f57 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -537,7 +537,6 @@ lives_below_in_same_fs(struct dentry *d, struct dentry *dentry) static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) { struct vfsmount *res, *p, *q, *r, *s; - struct list_head *h; struct nameidata nd; res = q = clone_mnt(mnt, dentry); @@ -546,8 +545,7 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) q->mnt_mountpoint = mnt->mnt_mountpoint; p = mnt; - for (h = mnt->mnt_mounts.next; h != &mnt->mnt_mounts; h = h->next) { - r = list_entry(h, struct vfsmount, mnt_child); + list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) { if (!lives_below_in_same_fs(r->mnt_mountpoint, dentry)) continue; -- GitLab From 0cdca3f9806a3dbaa07b5e8175000cd513ba92d4 Mon Sep 17 00:00:00 2001 From: Domen Puncer <domen@coderock.org> Date: Sat, 10 Sep 2005 00:27:07 -0700 Subject: [PATCH 396/563] [PATCH] janitor: fs/dcache.c: list_for_each* First one is list_for_each_entry (thanks maks), second 2 list_for_each_safe. Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/dcache.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index a15a2e1f55208..7376b61269fb7 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -337,12 +337,10 @@ struct dentry * d_find_alias(struct inode *inode) */ void d_prune_aliases(struct inode *inode) { - struct list_head *tmp, *head = &inode->i_dentry; + struct dentry *dentry; restart: spin_lock(&dcache_lock); - tmp = head; - while ((tmp = tmp->next) != head) { - struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); + list_for_each_entry(dentry, &inode->i_dentry, d_alias) { spin_lock(&dentry->d_lock); if (!atomic_read(&dentry->d_count)) { __dget_locked(dentry); @@ -463,10 +461,7 @@ void shrink_dcache_sb(struct super_block * sb) * superblock to the most recent end of the unused list. */ spin_lock(&dcache_lock); - next = dentry_unused.next; - while (next != &dentry_unused) { - tmp = next; - next = tmp->next; + list_for_each_safe(tmp, next, &dentry_unused) { dentry = list_entry(tmp, struct dentry, d_lru); if (dentry->d_sb != sb) continue; @@ -478,10 +473,7 @@ void shrink_dcache_sb(struct super_block * sb) * Pass two ... free the dentries for this superblock. */ repeat: - next = dentry_unused.next; - while (next != &dentry_unused) { - tmp = next; - next = tmp->next; + list_for_each_safe(tmp, next, &dentry_unused) { dentry = list_entry(tmp, struct dentry, d_lru); if (dentry->d_sb != sb) continue; -- GitLab From 80ce45fd961ba8c951adc9857bfda87102b1f5b1 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:08 -0700 Subject: [PATCH 397/563] [PATCH] janitor: ide-tape: replace schedule_timeout() with msleep() Uses msleep() instead of schedule_timeout() to guarantee the task delays at least the desired time amount. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/ide/ide-tape.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 5a3dc46008e64..ee38e6b143a4c 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -2903,8 +2903,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) } else if (!(tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) return -EIO; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ / 10); + msleep(100); } return -EIO; } -- GitLab From 46308c0bbbb066305e0798a2fa03328467a3c7d6 Mon Sep 17 00:00:00 2001 From: Domen Puncer <domen@coderock.org> Date: Sat, 10 Sep 2005 00:27:09 -0700 Subject: [PATCH 398/563] [PATCH] janitor: block/umem: replace PRINTK with pr_debug Removed unused dprintk, replaced PRINTK with pr_debug. Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/block/umem.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 0c4c121d2e796..0f48301342da4 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -34,6 +34,7 @@ * - set initialised bit then. */ +//#define DEBUG /* uncomment if you want debugging info (pr_debug) */ #include <linux/config.h> #include <linux/sched.h> #include <linux/fs.h> @@ -58,10 +59,6 @@ #include <asm/uaccess.h> #include <asm/io.h> -#define PRINTK(x...) do {} while (0) -#define dprintk(x...) do {} while (0) -/*#define dprintk(x...) printk(x) */ - #define MM_MAXCARDS 4 #define MM_RAHEAD 2 /* two sectors */ #define MM_BLKSIZE 1024 /* 1k blocks */ @@ -299,7 +296,7 @@ static void mm_start_io(struct cardinfo *card) /* make the last descriptor end the chain */ page = &card->mm_pages[card->Active]; - PRINTK("start_io: %d %d->%d\n", card->Active, page->headcnt, page->cnt-1); + pr_debug("start_io: %d %d->%d\n", card->Active, page->headcnt, page->cnt-1); desc = &page->desc[page->cnt-1]; desc->control_bits |= cpu_to_le32(DMASCR_CHAIN_COMP_EN); @@ -532,7 +529,7 @@ static void process_page(unsigned long data) activate(card); } else { /* haven't finished with this one yet */ - PRINTK("do some more\n"); + pr_debug("do some more\n"); mm_start_io(card); } out_unlock: @@ -555,7 +552,7 @@ static void process_page(unsigned long data) static int mm_make_request(request_queue_t *q, struct bio *bio) { struct cardinfo *card = q->queuedata; - PRINTK("mm_make_request %ld %d\n", bh->b_rsector, bh->b_size); + pr_debug("mm_make_request %ld %d\n", bh->b_rsector, bh->b_size); bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/ spin_lock_irq(&card->lock); -- GitLab From 0c5719c43d34073f6b4b0a2dd99f5317a5f63abd Mon Sep 17 00:00:00 2001 From: Domen Puncer <domen@coderock.org> Date: Sat, 10 Sep 2005 00:27:10 -0700 Subject: [PATCH 399/563] [PATCH] janitor: tulip/de4x5: list_for_each s/for/list_for_each/ Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Cc: Jeff Garzik <jgarzik@pobox.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/net/tulip/de4x5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 93800c126e866..ee48bfd673493 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -2144,9 +2144,9 @@ srom_search(struct net_device *dev, struct pci_dev *pdev) u_long iobase = 0; /* Clear upper 32 bits in Alphas */ int i, j, cfrv; struct de4x5_private *lp = netdev_priv(dev); - struct list_head *walk = &pdev->bus_list; + struct list_head *walk; - for (walk = walk->next; walk != &pdev->bus_list; walk = walk->next) { + list_for_each(walk, &pdev->bus_list) { struct pci_dev *this_dev = pci_dev_b(walk); /* Skip the pci_bus list entry */ -- GitLab From 0e8bbf59bd1ff78ad7e6c7afe6acef91372914e1 Mon Sep 17 00:00:00 2001 From: Michael Veeck <michael.veeck@gmx.net> Date: Sat, 10 Sep 2005 00:27:11 -0700 Subject: [PATCH 400/563] [PATCH] janitor: sh: bigsur/io: minmax-removal Patch removes unnecessary min/max macros and changes calls to use kernel.h macros instead. Signed-off-by: Michael Veeck <michael.veeck@gmx.net> Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Cc: Paul Mundt <lethal@linux-sh.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/sh/boards/bigsur/io.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/sh/boards/bigsur/io.c b/arch/sh/boards/bigsur/io.c index 697144de74194..a9fde781b21ac 100644 --- a/arch/sh/boards/bigsur/io.c +++ b/arch/sh/boards/bigsur/io.c @@ -37,10 +37,6 @@ static u8 bigsur_iomap_lo_shift[BIGSUR_IOMAP_LO_NMAP]; static u32 bigsur_iomap_hi[BIGSUR_IOMAP_HI_NMAP]; static u8 bigsur_iomap_hi_shift[BIGSUR_IOMAP_HI_NMAP]; -#ifndef MAX -#define MAX(a,b) ((a)>(b)?(a):(b)) -#endif - void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift) { u32 port, endport = baseport + nports; @@ -57,7 +53,7 @@ void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift) addr += (1<<(BIGSUR_IOMAP_LO_SHIFT)); } - for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ; + for (port = max_t(u32, baseport, BIGSUR_IOMAP_LO_THRESH); port < endport && port < BIGSUR_IOMAP_HI_THRESH ; port += (1<<BIGSUR_IOMAP_HI_SHIFT)) { pr_debug(" maphi[0x%x] = 0x%08x\n", port, addr); @@ -80,7 +76,7 @@ void bigsur_port_unmap(u32 baseport, u32 nports) bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = 0; } - for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ; + for (port = max_t(u32, baseport, BIGSUR_IOMAP_LO_THRESH); port < endport && port < BIGSUR_IOMAP_HI_THRESH ; port += (1<<BIGSUR_IOMAP_HI_SHIFT)) { bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = 0; -- GitLab From 31a34571e5eed7cb1d70d5e7edd013261fe602e9 Mon Sep 17 00:00:00 2001 From: Michael Veeck <michael.veeck@gmx.net> Date: Sat, 10 Sep 2005 00:27:13 -0700 Subject: [PATCH 401/563] [PATCH] janitor: sh: hd64465: minmax-removal Patch removes unnecessary min/max macros and changes calls to use kernel.h macros instead. Signed-off-by: Michael Veeck <michael.veeck@gmx.net> Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/sh/cchips/hd6446x/hd64465/io.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/sh/cchips/hd6446x/hd64465/io.c b/arch/sh/cchips/hd6446x/hd64465/io.c index 99ac709c550e9..84cb142def0b1 100644 --- a/arch/sh/cchips/hd6446x/hd64465/io.c +++ b/arch/sh/cchips/hd6446x/hd64465/io.c @@ -48,10 +48,6 @@ static unsigned char hd64465_iomap_lo_shift[HD64465_IOMAP_LO_NMAP]; static unsigned long hd64465_iomap_hi[HD64465_IOMAP_HI_NMAP]; static unsigned char hd64465_iomap_hi_shift[HD64465_IOMAP_HI_NMAP]; -#ifndef MAX -#define MAX(a,b) ((a)>(b)?(a):(b)) -#endif - #define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x)) void hd64465_port_map(unsigned short baseport, unsigned int nports, @@ -71,7 +67,7 @@ void hd64465_port_map(unsigned short baseport, unsigned int nports, addr += (1<<(HD64465_IOMAP_LO_SHIFT)); } - for (port = MAX(baseport, HD64465_IOMAP_LO_THRESH) ; + for (port = max_t(unsigned int, baseport, HD64465_IOMAP_LO_THRESH); port < endport && port < HD64465_IOMAP_HI_THRESH ; port += (1<<HD64465_IOMAP_HI_SHIFT)) { DPRINTK(" maphi[0x%x] = 0x%08lx\n", port, addr); @@ -95,7 +91,7 @@ void hd64465_port_unmap(unsigned short baseport, unsigned int nports) hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = 0; } - for (port = MAX(baseport, HD64465_IOMAP_LO_THRESH) ; + for (port = max_t(unsigned int, baseport, HD64465_IOMAP_LO_THRESH); port < endport && port < HD64465_IOMAP_HI_THRESH ; port += (1<<HD64465_IOMAP_HI_SHIFT)) { hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = 0; -- GitLab From f6a2f3404a3b09281a264058fa8dd318bac51178 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:14 -0700 Subject: [PATCH 402/563] [PATCH] janitor: block/xd: replace schedule_timeout() with msleep()/msleep_interruptible() Use msleep() or msleep_interruptible() [as appropriate] instead of schedule_timeout() to gurantee the task delays as expected. As a result changed the units of the timeout variable from jiffies to msecs. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/block/xd.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 1676033da6c6f..2c6d3423496b3 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -47,6 +47,7 @@ #include <linux/wait.h> #include <linux/blkdev.h> #include <linux/blkpg.h> +#include <linux/delay.h> #include <asm/system.h> #include <asm/io.h> @@ -62,7 +63,7 @@ static int xd[5] = { -1,-1,-1,-1, }; #define XD_DONT_USE_DMA 0 /* Initial value. may be overriden using "nodma" module option */ -#define XD_INIT_DISK_DELAY (30*HZ/1000) /* 30 ms delay during disk initialization */ +#define XD_INIT_DISK_DELAY (30) /* 30 ms delay during disk initialization */ /* Above may need to be increased if a problem with the 2nd drive detection (ST11M controller) or resetting a controller (WD) appears */ @@ -633,14 +634,12 @@ static u_char __init xd_initdrives (void (*init_drive)(u_char drive)) for (i = 0; i < XD_MAXDRIVES; i++) { xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0); if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT*8)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(XD_INIT_DISK_DELAY); + msleep_interruptible(XD_INIT_DISK_DELAY); init_drive(count); count++; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(XD_INIT_DISK_DELAY); + msleep_interruptible(XD_INIT_DISK_DELAY); } } return (count); @@ -761,8 +760,7 @@ static void __init xd_wd_init_controller (unsigned int address) outb(0,XD_RESET); /* reset the controller */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(XD_INIT_DISK_DELAY); + msleep(XD_INIT_DISK_DELAY); } static void __init xd_wd_init_drive (u_char drive) @@ -936,8 +934,7 @@ If you need non-standard settings use the xd=... command */ xd_maxsectors = 0x01; outb(0,XD_RESET); /* reset the controller */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(XD_INIT_DISK_DELAY); + msleep(XD_INIT_DISK_DELAY); } static void __init xd_xebec_init_drive (u_char drive) -- GitLab From 2aad5f03d97bbaf1b19f31347656de953247c7da Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:15 -0700 Subject: [PATCH 403/563] [PATCH] janitor: ide/ide-cs: replace schedule_timeout() with msleep() Uses msleep() in place of schedule_timeout() to guarantee the task delays as expected. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Maximilian Attems <janitor@sternwelten.at> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/ide/legacy/ide-cs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index dc0841b2721c6..0ccf85fcee347 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -43,6 +43,7 @@ #include <linux/ide.h> #include <linux/hdreg.h> #include <linux/major.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/system.h> @@ -340,8 +341,7 @@ static void ide_config(dev_link_t *link) break; } } - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); } if (hd < 0) { -- GitLab From ea0e0a4f53a75ed9d0812352c0410f6fc2a0b62a Mon Sep 17 00:00:00 2001 From: James Lamanna <jlamanna@gmail.com> Date: Sat, 10 Sep 2005 00:27:16 -0700 Subject: [PATCH 404/563] [PATCH] janitor: reiserfs: super.c - vfree() checking cleanups super.c vfree() checking cleanups. Signed-off by: James Lamanna <jlamanna@gmail.com> Signed-off-by: Domen Puncer <domen@coderock.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/reiserfs/super.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 6951c35755beb..44b02fc02ebef 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1934,8 +1934,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) if (SB_AP_BITMAP(s)) brelse(SB_AP_BITMAP(s)[j].bh); } - if (SB_AP_BITMAP(s)) - vfree(SB_AP_BITMAP(s)); + vfree(SB_AP_BITMAP(s)); } if (SB_BUFFER_WITH_SB(s)) brelse(SB_BUFFER_WITH_SB(s)); -- GitLab From e2afe67453e5b1499459ee3596b1e7924a5208f5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:27:16 -0700 Subject: [PATCH 405/563] [PATCH] include/asm-i386/: "extern inline" -> "static inline" "extern inline" doesn't make much sense. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-i386/div64.h | 2 +- include/asm-i386/processor.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-i386/div64.h b/include/asm-i386/div64.h index 28ed8b296afc1..75c67c785bb8d 100644 --- a/include/asm-i386/div64.h +++ b/include/asm-i386/div64.h @@ -35,7 +35,7 @@ */ #define div_long_long_rem(a,b,c) div_ll_X_l_rem(a,b,c) -extern inline long +static inline long div_ll_X_l_rem(long long divs, long div, long *rem) { long dum2; diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 37bef8ed7bed1..0a4ec764377ca 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -679,7 +679,7 @@ static inline void rep_nop(void) However we don't do prefetches for pre XP Athlons currently That should be fixed. */ #define ARCH_HAS_PREFETCH -extern inline void prefetch(const void *x) +static inline void prefetch(const void *x) { alternative_input(ASM_NOP4, "prefetchnta (%1)", @@ -693,7 +693,7 @@ extern inline void prefetch(const void *x) /* 3dnow! prefetch to get an exclusive cache line. Useful for spinlocks to avoid one state transition in the cache coherency protocol. */ -extern inline void prefetchw(const void *x) +static inline void prefetchw(const void *x) { alternative_input(ASM_NOP4, "prefetchw (%1)", -- GitLab From 2befb9e36dc52d715c3a67a9dbad36ac1edc376f Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:27:17 -0700 Subject: [PATCH 406/563] [PATCH] include/linux/blkdev.h: "extern inline" -> "static inline" "extern inline" doesn't make much sense. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/blkdev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index aefa26fbae8ad..efdc9b5bc05c8 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -728,7 +728,7 @@ static inline unsigned int blksize_bits(unsigned int size) return bits; } -extern inline unsigned int block_size(struct block_device *bdev) +static inline unsigned int block_size(struct block_device *bdev) { return bdev->bd_block_size; } -- GitLab From 9adeb1b409e832c31d93106ce52482a5f0078439 Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:27:18 -0700 Subject: [PATCH 407/563] [PATCH] "extern inline" -> "static inline" "extern inline" doesn't make much sense. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/reiserfs_fs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index 17e458e17e2bb..af00b10294cde 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -2097,7 +2097,7 @@ void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *, b_blocknr_t, int for_unformatted); int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t *, int, int); -extern inline int reiserfs_new_form_blocknrs(struct tree_balance *tb, +static inline int reiserfs_new_form_blocknrs(struct tree_balance *tb, b_blocknr_t * new_blocknrs, int amount_needed) { @@ -2113,7 +2113,7 @@ extern inline int reiserfs_new_form_blocknrs(struct tree_balance *tb, 0); } -extern inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle +static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle *th, struct inode *inode, b_blocknr_t * new_blocknrs, struct path *path, long block) @@ -2130,7 +2130,7 @@ extern inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle } #ifdef REISERFS_PREALLOCATE -extern inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle +static inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle *th, struct inode *inode, b_blocknr_t * new_blocknrs, struct path *path, long block) -- GitLab From c2d08dade7743bd3a28cc5f68163e71c00a2a908 Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:27:18 -0700 Subject: [PATCH 408/563] [PATCH] include/linux/bio.h: "extern inline" -> "static inline" "extern inline" doesn't make much sense. Signed-off-by: Adrian Bunk <bunk@stusta.de> Acked-by: Jens Axboe <axboe@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/bio.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/linux/bio.h b/include/linux/bio.h index cdaf03a14a511..6e1c79c8b6bfd 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -314,9 +314,8 @@ void zero_fill_bio(struct bio *bio); * bvec_kmap_irq and bvec_kunmap_irq!! * * This function MUST be inlined - it plays with the CPU interrupt flags. - * Hence the `extern inline'. */ -extern inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags) +static inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags) { unsigned long addr; @@ -332,7 +331,7 @@ extern inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags) return (char *) addr + bvec->bv_offset; } -extern inline void bvec_kunmap_irq(char *buffer, unsigned long *flags) +static inline void bvec_kunmap_irq(char *buffer, unsigned long *flags) { unsigned long ptr = (unsigned long) buffer & PAGE_MASK; @@ -345,7 +344,7 @@ extern inline void bvec_kunmap_irq(char *buffer, unsigned long *flags) #define bvec_kunmap_irq(buf, flags) do { *(flags) = 0; } while (0) #endif -extern inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx, +static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx, unsigned long *flags) { return bvec_kmap_irq(bio_iovec_idx(bio, idx), flags); -- GitLab From b01d8684e9e5b04270970c97df856d47668267e3 Mon Sep 17 00:00:00 2001 From: Pavel Machek <pavel@suse.cz> Date: Sat, 10 Sep 2005 00:27:19 -0700 Subject: [PATCH 409/563] [PATCH] remove ACPI S4bios support Remove S4BIOS support. It is pretty useless, and only ever worked for _me_ once. (I do not think anyone else ever tried it). It was in feature-removal for a long time, and it should have been removed before. Signed-off-by: Pavel Machek <pavel@suse.cz> Signed-off-by: Adrian Bunk <bunk@stusta.de> Cc: "Brown, Len" <len.brown@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/feature-removal-schedule.txt | 8 -------- arch/i386/kernel/acpi/wakeup.S | 6 ------ drivers/acpi/sleep/main.c | 8 -------- drivers/acpi/sleep/poweroff.c | 4 +--- drivers/acpi/sleep/proc.c | 2 -- 5 files changed, 1 insertion(+), 27 deletions(-) diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 5f95d4b3cab1a..784e08c1c80a3 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -17,14 +17,6 @@ Who: Greg Kroah-Hartman <greg@kroah.com> --------------------------- -What: ACPI S4bios support -When: May 2005 -Why: Noone uses it, and it probably does not work, anyway. swsusp is - faster, more reliable, and people are actually using it. -Who: Pavel Machek <pavel@suse.cz> - ---------------------------- - What: io_remap_page_range() (macro or function) When: September 2005 Why: Replaced by io_remap_pfn_range() which allows more memory space diff --git a/arch/i386/kernel/acpi/wakeup.S b/arch/i386/kernel/acpi/wakeup.S index 44d886c745ecc..7c74fe0dc93c1 100644 --- a/arch/i386/kernel/acpi/wakeup.S +++ b/arch/i386/kernel/acpi/wakeup.S @@ -304,12 +304,6 @@ ret_point: call restore_processor_state ret -ENTRY(do_suspend_lowlevel_s4bios) - call save_processor_state - call save_registers - call acpi_enter_sleep_state_s4bios - ret - ALIGN # saved registers saved_gdt: .long 0,0 diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 7249ba2b7a274..aee50b4532659 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -23,7 +23,6 @@ u8 sleep_states[ACPI_S_STATE_COUNT]; static struct pm_ops acpi_pm_ops; -extern void do_suspend_lowlevel_s4bios(void); extern void do_suspend_lowlevel(void); static u32 acpi_suspend_states[] = { @@ -98,8 +97,6 @@ static int acpi_pm_enter(suspend_state_t pm_state) case PM_SUSPEND_DISK: if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM) status = acpi_enter_sleep_state(acpi_state); - else - do_suspend_lowlevel_s4bios(); break; case PM_SUSPEND_MAX: acpi_power_off(); @@ -206,11 +203,6 @@ static int __init acpi_sleep_init(void) printk(" S%d", i); } if (i == ACPI_STATE_S4) { - if (acpi_gbl_FACS->S4bios_f) { - sleep_states[i] = 1; - printk(" S4bios"); - acpi_pm_ops.pm_disk_mode = PM_DISK_FIRMWARE; - } if (sleep_states[i]) acpi_pm_ops.pm_disk_mode = PM_DISK_PLATFORM; } diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index a5f947de879bc..af7935a95bcc8 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c @@ -21,9 +21,7 @@ int acpi_sleep_prepare(u32 acpi_state) { #ifdef CONFIG_ACPI_SLEEP /* do we have a wakeup address for S2 and S3? */ - /* Here, we support only S4BIOS, those we set the wakeup address */ - /* S4OS is only supported for now via swsusp.. */ - if (acpi_state == ACPI_STATE_S3 || acpi_state == ACPI_STATE_S4) { + if (acpi_state == ACPI_STATE_S3) { if (!acpi_wakeup_address) { return -EFAULT; } diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 09a603f3523ec..4696a85a98b92 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -25,8 +25,6 @@ static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) for (i = 0; i <= ACPI_STATE_S5; i++) { if (sleep_states[i]) { seq_printf(seq, "S%d ", i); - if (i == ACPI_STATE_S4 && acpi_gbl_FACS->S4bios_f) - seq_printf(seq, "S4bios "); } } -- GitLab From e711700a0e6a6824fcfd5519d6b6982850a648ee Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:27:20 -0700 Subject: [PATCH 410/563] [PATCH] fs/cramfs/uncompress.c should #include <linux/cramfs_fs.h> Every file should #include the header with the prototypes of the global functions it is offering. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/cramfs/uncompress.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c index 5034365b06a86..8def89f2c4383 100644 --- a/fs/cramfs/uncompress.c +++ b/fs/cramfs/uncompress.c @@ -19,6 +19,7 @@ #include <linux/errno.h> #include <linux/vmalloc.h> #include <linux/zlib.h> +#include <linux/cramfs_fs.h> static z_stream stream; static int initialized; -- GitLab From 672289e9faa56acd4e39ad866ea258b7be7c99a6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Sat, 10 Sep 2005 00:27:21 -0700 Subject: [PATCH 411/563] [PATCH] i386/x86_64: make get_cpu_vendor() static get_cpu_vendor() no longer has any users in other files. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/kernel/cpu/common.c | 2 +- arch/x86_64/kernel/setup.c | 2 +- include/asm-x86_64/proto.h | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 46ce9b248f551..9ad43be9a01f0 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -151,7 +151,7 @@ static char __devinit *table_lookup_model(struct cpuinfo_x86 *c) } -void __devinit get_cpu_vendor(struct cpuinfo_x86 *c, int early) +static void __devinit get_cpu_vendor(struct cpuinfo_x86 *c, int early) { char *v = c->x86_vendor_id; int i; diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 0511d8087910d..9aec524be3ebb 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -929,7 +929,7 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) c->x86_num_cores = intel_num_cpu_cores(c); } -void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c) +static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index 6c813eb521f33..f7574196424e1 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -8,7 +8,6 @@ struct cpuinfo_x86; struct pt_regs; -extern void get_cpu_vendor(struct cpuinfo_x86*); extern void start_kernel(void); extern void pda_init(int); -- GitLab From 64ed93a268bc18fa6f72f61420d0e0022c5e38d1 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:21 -0700 Subject: [PATCH 412/563] [PATCH] add schedule_timeout_{,un}interruptible() interfaces Add schedule_timeout_{,un}interruptible() interfaces so that schedule_timeout() callers don't have to worry about forgetting to add the set_current_state() call beforehand. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/sched.h | 2 ++ kernel/timer.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/linux/sched.h b/include/linux/sched.h index ac70f845b5b1d..4b83cb230006a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -203,6 +203,8 @@ extern int in_sched_functions(unsigned long addr); #define MAX_SCHEDULE_TIMEOUT LONG_MAX extern signed long FASTCALL(schedule_timeout(signed long timeout)); +extern signed long schedule_timeout_interruptible(signed long timeout); +extern signed long schedule_timeout_uninterruptible(signed long timeout); asmlinkage void schedule(void); struct namespace; diff --git a/kernel/timer.c b/kernel/timer.c index 13e2b513be019..a0b716d62701d 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1154,6 +1154,20 @@ fastcall signed long __sched schedule_timeout(signed long timeout) EXPORT_SYMBOL(schedule_timeout); +signed long __sched schedule_timeout_interruptible(signed long timeout) +{ + set_current_state(TASK_INTERRUPTIBLE); + return schedule_timeout(timeout); +} +EXPORT_SYMBOL(schedule_timeout_interruptible); + +signed long __sched schedule_timeout_uninterruptible(signed long timeout) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + return schedule_timeout(timeout); +} +EXPORT_SYMBOL(schedule_timeout_uninterruptible); + /* Thread ID - the internal kernel "pid" */ asmlinkage long sys_gettid(void) { -- GitLab From 84f902c0903a98a315b45a4fba3d2ac0de388256 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:22 -0700 Subject: [PATCH 413/563] [PATCH] include: update jiffies/{m,u}secs conversion functions Clarify the human-time units to jiffies conversion functions by using the constants in time.h. This makes many of the subsequent patches direct copies of the current code. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/jiffies.h | 40 ++++++++++++++++++++-------------------- include/linux/time.h | 2 ++ 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index d7a2555a886c3..6acfdbba734b1 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -254,23 +254,23 @@ static inline u64 get_jiffies_64(void) */ static inline unsigned int jiffies_to_msecs(const unsigned long j) { -#if HZ <= 1000 && !(1000 % HZ) - return (1000 / HZ) * j; -#elif HZ > 1000 && !(HZ % 1000) - return (j + (HZ / 1000) - 1)/(HZ / 1000); +#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) + return (MSEC_PER_SEC / HZ) * j; +#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) + return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC); #else - return (j * 1000) / HZ; + return (j * MSEC_PER_SEC) / HZ; #endif } static inline unsigned int jiffies_to_usecs(const unsigned long j) { -#if HZ <= 1000000 && !(1000000 % HZ) - return (1000000 / HZ) * j; -#elif HZ > 1000000 && !(HZ % 1000000) - return (j + (HZ / 1000000) - 1)/(HZ / 1000000); +#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) + return (USEC_PER_SEC / HZ) * j; +#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC) + return (j + (HZ / USEC_PER_SEC) - 1)/(HZ / USEC_PER_SEC); #else - return (j * 1000000) / HZ; + return (j * USEC_PER_SEC) / HZ; #endif } @@ -278,12 +278,12 @@ static inline unsigned long msecs_to_jiffies(const unsigned int m) { if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET)) return MAX_JIFFY_OFFSET; -#if HZ <= 1000 && !(1000 % HZ) - return (m + (1000 / HZ) - 1) / (1000 / HZ); -#elif HZ > 1000 && !(HZ % 1000) - return m * (HZ / 1000); +#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) + return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ); +#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) + return m * (HZ / MSEC_PER_SEC); #else - return (m * HZ + 999) / 1000; + return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC; #endif } @@ -291,12 +291,12 @@ static inline unsigned long usecs_to_jiffies(const unsigned int u) { if (u > jiffies_to_usecs(MAX_JIFFY_OFFSET)) return MAX_JIFFY_OFFSET; -#if HZ <= 1000000 && !(1000000 % HZ) - return (u + (1000000 / HZ) - 1) / (1000000 / HZ); -#elif HZ > 1000000 && !(HZ % 1000000) - return u * (HZ / 1000000); +#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) + return (u + (USEC_PER_SEC / HZ) - 1) / (USEC_PER_SEC / HZ); +#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC) + return u * (HZ / USEC_PER_SEC); #else - return (u * HZ + 999999) / 1000000; + return (u * HZ + USEC_PER_SEC - 1) / USEC_PER_SEC; #endif } diff --git a/include/linux/time.h b/include/linux/time.h index c10d4c21c1839..36fb2ef13cff5 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -28,6 +28,8 @@ struct timezone { #ifdef __KERNEL__ /* Parameters used to convert the timespec values */ +#define MSEC_PER_SEC (1000L) + #ifndef USEC_PER_SEC #define USEC_PER_SEC (1000000L) #endif -- GitLab From 373016e9e1353f2af871993d27d00768f08cc883 Mon Sep 17 00:00:00 2001 From: Andrew Morton <akpm@osdl.org> Date: Sat, 10 Sep 2005 00:27:23 -0700 Subject: [PATCH 414/563] [PATCH] time.h: remove ifdefs Remove these ifdefs - there's no need to have more than one definition of these multipliers anywhere. Cc: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/time.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/linux/time.h b/include/linux/time.h index 36fb2ef13cff5..8e83f4e778bb1 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -29,18 +29,9 @@ struct timezone { /* Parameters used to convert the timespec values */ #define MSEC_PER_SEC (1000L) - -#ifndef USEC_PER_SEC #define USEC_PER_SEC (1000000L) -#endif - -#ifndef NSEC_PER_SEC #define NSEC_PER_SEC (1000000000L) -#endif - -#ifndef NSEC_PER_USEC #define NSEC_PER_USEC (1000L) -#endif static __inline__ int timespec_equal(struct timespec *a, struct timespec *b) { -- GitLab From 041e0e3b1970c508dc9a95b7dd9dc86271a7d7ac Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:23 -0700 Subject: [PATCH 415/563] [PATCH] fs: fix-up schedule_timeout() usage Use schedule_timeout_{,un}interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Also use helper functions to convert between human time units and jiffies rather than constant HZ division to avoid rounding errors. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- fs/cifs/connect.c | 6 ++---- fs/jbd/transaction.c | 3 +-- fs/lockd/clntproc.c | 3 +-- fs/nfs/nfs3proc.c | 3 +-- fs/nfs/nfs4proc.c | 12 ++++-------- fs/reiserfs/journal.c | 3 +-- fs/smbfs/proc.c | 3 +-- fs/xfs/linux-2.6/time.h | 3 +-- fs/xfs/linux-2.6/xfs_buf.c | 6 +++--- fs/xfs/linux-2.6/xfs_super.c | 12 ++++++------ 10 files changed, 21 insertions(+), 33 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3217ac5f6bd7a..2335f14a15830 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3215,10 +3215,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) } cifs_sb->tcon = NULL; - if (ses) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); - } + if (ses) + schedule_timeout_interruptible(msecs_to_jiffies(500)); if (ses) sesInfoFree(ses); diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index c6ec66fd87668..49bbc2be3d729 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1340,8 +1340,7 @@ int journal_stop(handle_t *handle) if (handle->h_sync) { do { old_handle_count = transaction->t_handle_count; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (old_handle_count != transaction->t_handle_count); } diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 14b3ce87fa29c..87332f30141b6 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -299,8 +299,7 @@ nlmclnt_alloc_call(void) return call; } printk("nlmclnt_alloc_call: failed, waiting for memory\n"); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(5*HZ); + schedule_timeout_interruptible(5*HZ); } return NULL; } diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 2681485cf2d00..edc95514046d5 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -34,8 +34,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) res = rpc_call_sync(clnt, msg, flags); if (res != -EJUKEBOX) break; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(NFS_JUKEBOX_RETRY_TIME); + schedule_timeout_interruptible(NFS_JUKEBOX_RETRY_TIME); res = -ERESTARTSYS; } while (!signalled()); rpc_clnt_sigunmask(clnt, &oldset); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 0c5a308e49638..9701ca8c94285 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2418,14 +2418,11 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) *timeout = NFS4_POLL_RETRY_MAX; rpc_clnt_sigmask(clnt, &oldset); if (clnt->cl_intr) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(*timeout); + schedule_timeout_interruptible(*timeout); if (signalled()) res = -ERESTARTSYS; - } else { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(*timeout); - } + } else + schedule_timeout_uninterruptible(*timeout); rpc_clnt_sigunmask(clnt, &oldset); *timeout <<= 1; return res; @@ -2578,8 +2575,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4 static unsigned long nfs4_set_lock_task_retry(unsigned long timeout) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(timeout); + schedule_timeout_interruptible(timeout); timeout <<= 1; if (timeout > NFS4_LOCK_MAXTIMEOUT) return NFS4_LOCK_MAXTIMEOUT; diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index a8e29e9bbbd08..4b15761434bc7 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2868,8 +2868,7 @@ static void let_transaction_grow(struct super_block *sb, unsigned long trans_id) struct reiserfs_journal *journal = SB_JOURNAL(sb); unsigned long bcount = journal->j_bcount; while (1) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); journal->j_current_jl->j_state |= LIST_COMMIT_PENDING; while ((atomic_read(&journal->j_wcount) > 0 || atomic_read(&journal->j_jlock)) && diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index 220babe91efd1..38ab558835c4b 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -2397,8 +2397,7 @@ smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir, if (req->rq_rcls == ERRSRV && req->rq_err == ERRerror) { /* a damn Win95 bug - sometimes it clags if you ask it too fast */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/5); + schedule_timeout_interruptible(msecs_to_jiffies(200)); continue; } diff --git a/fs/xfs/linux-2.6/time.h b/fs/xfs/linux-2.6/time.h index 6c6fd0faa8e1f..b0d2873ab2747 100644 --- a/fs/xfs/linux-2.6/time.h +++ b/fs/xfs/linux-2.6/time.h @@ -39,8 +39,7 @@ typedef struct timespec timespec_t; static inline void delay(long ticks) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(ticks); + schedule_timeout_uninterruptible(ticks); } static inline void nanotime(struct timespec *tvp) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 655bf4a78afeb..e82cf72ac599a 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1780,10 +1780,10 @@ xfsbufd( xfsbufd_force_sleep = 0; } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout((xfs_buf_timer_centisecs * HZ) / 100); + schedule_timeout_interruptible + (xfs_buf_timer_centisecs * msecs_to_jiffies(10)); - age = (xfs_buf_age_centisecs * HZ) / 100; + age = xfs_buf_age_centisecs * msecs_to_jiffies(10); spin_lock(&pbd_delwrite_lock); list_for_each_entry_safe(pb, n, &pbd_delwrite_queue, pb_list) { PB_TRACE(pb, "walkq1", (long)pagebuf_ispin(pb)); diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 0da87bfc99999..2302454d8d479 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -467,7 +467,7 @@ xfs_flush_inode( igrab(inode); xfs_syncd_queue_work(vfs, inode, xfs_flush_inode_work); - delay(HZ/2); + delay(msecs_to_jiffies(500)); } /* @@ -492,7 +492,7 @@ xfs_flush_device( igrab(inode); xfs_syncd_queue_work(vfs, inode, xfs_flush_device_work); - delay(HZ/2); + delay(msecs_to_jiffies(500)); xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); } @@ -520,10 +520,9 @@ xfssyncd( struct vfs_sync_work *work, *n; LIST_HEAD (tmp); - timeleft = (xfs_syncd_centisecs * HZ) / 100; + timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - timeleft = schedule_timeout(timeleft); + timeleft = schedule_timeout_interruptible(timeleft); /* swsusp */ try_to_freeze(); if (kthread_should_stop()) @@ -537,7 +536,8 @@ xfssyncd( */ if (!timeleft || list_empty(&vfsp->vfs_sync_list)) { if (!timeleft) - timeleft = (xfs_syncd_centisecs * HZ) / 100; + timeleft = xfs_syncd_centisecs * + msecs_to_jiffies(10); INIT_LIST_HEAD(&vfsp->vfs_sync_work.w_list); list_add_tail(&vfsp->vfs_sync_work.w_list, &vfsp->vfs_sync_list); -- GitLab From 75bcc8c5e1de78616b04ef9f317a293a7c1c163c Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:24 -0700 Subject: [PATCH 416/563] [PATCH] kernel: fix-up schedule_timeout() usage Use schedule_timeout_{,un}interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/compat.c | 9 +++------ kernel/signal.c | 3 +-- kernel/timer.c | 18 ++++++------------ 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/kernel/compat.c b/kernel/compat.c index ddfcaaa86623a..102296e21ea86 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -48,8 +48,7 @@ static long compat_nanosleep_restart(struct restart_block *restart) if (!time_after(expire, now)) return 0; - current->state = TASK_INTERRUPTIBLE; - expire = schedule_timeout(expire - now); + expire = schedule_timeout_interruptible(expire - now); if (expire == 0) return 0; @@ -82,8 +81,7 @@ asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, return -EINVAL; expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); - current->state = TASK_INTERRUPTIBLE; - expire = schedule_timeout(expire); + expire = schedule_timeout_interruptible(expire); if (expire == 0) return 0; @@ -795,8 +793,7 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - current->state = TASK_INTERRUPTIBLE; - timeout = schedule_timeout(timeout); + timeout = schedule_timeout_interruptible(timeout); spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &s, &info); diff --git a/kernel/signal.c b/kernel/signal.c index 4980a073237ff..b92c3c9f8b9a2 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -2221,8 +2221,7 @@ sys_rt_sigtimedwait(const sigset_t __user *uthese, recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - current->state = TASK_INTERRUPTIBLE; - timeout = schedule_timeout(timeout); + timeout = schedule_timeout_interruptible(timeout); try_to_freeze(); spin_lock_irq(¤t->sighand->siglock); diff --git a/kernel/timer.c b/kernel/timer.c index a0b716d62701d..f4152fcd9f8ef 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1184,8 +1184,7 @@ static long __sched nanosleep_restart(struct restart_block *restart) if (!time_after(expire, now)) return 0; - current->state = TASK_INTERRUPTIBLE; - expire = schedule_timeout(expire - now); + expire = schedule_timeout_interruptible(expire - now); ret = 0; if (expire) { @@ -1213,8 +1212,7 @@ asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __us return -EINVAL; expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); - current->state = TASK_INTERRUPTIBLE; - expire = schedule_timeout(expire); + expire = schedule_timeout_interruptible(expire); ret = 0; if (expire) { @@ -1612,10 +1610,8 @@ void msleep(unsigned int msecs) { unsigned long timeout = msecs_to_jiffies(msecs) + 1; - while (timeout) { - set_current_state(TASK_UNINTERRUPTIBLE); - timeout = schedule_timeout(timeout); - } + while (timeout) + timeout = schedule_timeout_uninterruptible(timeout); } EXPORT_SYMBOL(msleep); @@ -1628,10 +1624,8 @@ unsigned long msleep_interruptible(unsigned int msecs) { unsigned long timeout = msecs_to_jiffies(msecs) + 1; - while (timeout && !signal_pending(current)) { - set_current_state(TASK_INTERRUPTIBLE); - timeout = schedule_timeout(timeout); - } + while (timeout && !signal_pending(current)) + timeout = schedule_timeout_interruptible(timeout); return jiffies_to_msecs(timeout); } -- GitLab From 13e4b57f6a4e23ceb99794a650d777e74831f4a6 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:25 -0700 Subject: [PATCH 417/563] [PATCH] mm: fix-up schedule_timeout() usage Use schedule_timeout_{,un}interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- mm/oom_kill.c | 3 +-- mm/swapfile.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 5ec8da12cfd98..ac3bf33e53701 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -300,6 +300,5 @@ void out_of_memory(unsigned int __nocast gfp_mask, int order) * Give "p" a good chance of killing itself before we * retry to allocate memory. */ - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); } diff --git a/mm/swapfile.c b/mm/swapfile.c index 4b6e8bf986bca..0184f510aacef 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1153,8 +1153,7 @@ asmlinkage long sys_swapoff(const char __user * specialfile) p->highest_bit = 0; /* cuts scans short */ while (p->flags >= SWP_SCANNING) { spin_unlock(&swap_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock(&swap_lock); } -- GitLab From 20c6abd1fd3a6296282f63fae82e589aa81862ff Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:25 -0700 Subject: [PATCH 418/563] [PATCH] alpha: fix-up schedule_timeout() usage Use schedule_timeout_interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Cc: Richard Henderson <rth@twiddle.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/alpha/kernel/osf_sys.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 2b034182a0ca8..0636116210d23 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -1154,8 +1154,7 @@ osf_usleep_thread(struct timeval32 __user *sleep, struct timeval32 __user *remai ticks = timeval_to_jiffies(&tmp); - current->state = TASK_INTERRUPTIBLE; - ticks = schedule_timeout(ticks); + ticks = schedule_timeout_interruptible(ticks); if (remain) { jiffies_to_timeval(ticks, &tmp); -- GitLab From 52e6e6308801697ae8e59e7a577f9ca71231a35c Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:26 -0700 Subject: [PATCH 419/563] [PATCH] i386: fix-up schedule_timeout() usage Use schedule_timeout_interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/kernel/io_apic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 1efdc76ae96df..35d3ce26a544a 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -573,8 +573,7 @@ static int balanced_irq(void *unused) } for ( ; ; ) { - set_current_state(TASK_INTERRUPTIBLE); - time_remaining = schedule_timeout(time_remaining); + time_remaining = schedule_timeout_interruptible(time_remaining); try_to_freeze(); if (time_after(jiffies, prev_balance_time+balanced_irq_interval)) { -- GitLab From 310b587e011ce02328c8e4c29eccd9f14d9007c5 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:27 -0700 Subject: [PATCH 420/563] [PATCH] mips: fix-up schedule_timeout() usage Use schedule_timeout_interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Also, replace custom timespectojiffies() function with globally availabe timespec_to_jiffies(). Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Cc: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/mips/kernel/irixsig.c | 17 ++--------------- arch/mips/kernel/sysirix.c | 3 +-- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 4c114ae21793e..eff89322ba506 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -440,18 +440,6 @@ struct irix5_siginfo { } stuff; }; -static inline unsigned long timespectojiffies(struct timespec *value) -{ - unsigned long sec = (unsigned) value->tv_sec; - long nsec = value->tv_nsec; - - if (sec > (LONG_MAX / HZ)) - return LONG_MAX; - nsec += 1000000000L / HZ - 1; - nsec /= 1000000000L / HZ; - return HZ * sec + nsec; -} - asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info, struct timespec *tp) { @@ -489,14 +477,13 @@ asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info, error = -EINVAL; goto out; } - expire = timespectojiffies(tp)+(tp->tv_sec||tp->tv_nsec); + expire = timespec_to_jiffies(tp) + (tp->tv_sec||tp->tv_nsec); } while(1) { long tmp = 0; - current->state = TASK_INTERRUPTIBLE; - expire = schedule_timeout(expire); + expire = schedule_timeout_interruptible(expire); for (i=0; i<=4; i++) tmp |= (current->pending.signal.sig[i] & kset.sig[i]); diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index b465954627178..4de155699c4fa 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -1032,8 +1032,7 @@ asmlinkage int irix_lseek64(int fd, int _unused, int offhi, int offlow, asmlinkage int irix_sginap(int ticks) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(ticks); + schedule_timeout_interruptible(ticks); return 0; } -- GitLab From 86e8486245a01f05a3267b2e8b5c02c2303b670d Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:28 -0700 Subject: [PATCH 421/563] [PATCH] drivers/block: fix-up schedule_timeout() usage Use schedule_timeout_{un,}interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Cc: Jens Axboe <axboe@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/block/cciss.c | 7 +++---- drivers/block/paride/pcd.c | 3 +-- drivers/block/paride/pf.c | 3 +-- drivers/block/paride/pg.c | 3 +-- drivers/block/paride/pt.c | 3 +-- drivers/block/swim3.c | 9 +++------ drivers/block/swim_iop.c | 3 +-- drivers/block/xd.c | 6 ++---- 8 files changed, 13 insertions(+), 24 deletions(-) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 418b1469d75d1..28f2c177a5416 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1713,10 +1713,9 @@ static unsigned long pollcomplete(int ctlr) for (i = 20 * HZ; i > 0; i--) { done = hba[ctlr]->access.command_completed(hba[ctlr]); - if (done == FIFO_EMPTY) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } else + if (done == FIFO_EMPTY) + schedule_timeout_uninterruptible(1); + else return (done); } /* Invalid address to tell caller we ran out of time */ diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 7289f67e95687..ac5ba462710b2 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -516,8 +516,7 @@ static int pcd_tray_move(struct cdrom_device_info *cdi, int position) static void pcd_sleep(int cs) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(cs); + schedule_timeout_interruptible(cs); } static int pcd_reset(struct pcd_unit *cd) diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 060b1f2a91ddc..711d2f314ac32 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -507,8 +507,7 @@ static void pf_eject(struct pf_unit *pf) static void pf_sleep(int cs) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(cs); + schedule_timeout_interruptible(cs); } /* the ATAPI standard actually specifies the contents of all 7 registers diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index 84d8e291ed964..b3982395f22b4 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -276,8 +276,7 @@ static inline u8 DRIVE(struct pg *dev) static void pg_sleep(int cs) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(cs); + schedule_timeout_interruptible(cs); } static int pg_wait(struct pg *dev, int go, int stop, unsigned long tmo, char *msg) diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index 5fe8ee86f095b..d8d35233cf495 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -383,8 +383,7 @@ static int pt_atapi(struct pt_unit *tape, char *cmd, int dlen, char *buf, char * static void pt_sleep(int cs) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(cs); + schedule_timeout_interruptible(cs); } static int pt_poll_dsc(struct pt_unit *tape, int pause, int tmo, char *msg) diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index e5f7494c00eed..e425ad3eebba8 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -834,8 +834,7 @@ static int fd_eject(struct floppy_state *fs) break; } swim3_select(fs, RELAX); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(1); if (swim3_readbit(fs, DISK_IN) == 0) break; } @@ -906,8 +905,7 @@ static int floppy_open(struct inode *inode, struct file *filp) break; } swim3_select(fs, RELAX); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(1); } if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0 || swim3_readbit(fs, DISK_IN) == 0)) @@ -992,8 +990,7 @@ static int floppy_revalidate(struct gendisk *disk) if (signal_pending(current)) break; swim3_select(fs, RELAX); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(1); } ret = swim3_readbit(fs, SEEK_COMPLETE) == 0 || swim3_readbit(fs, DISK_IN) == 0; diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c index a1283f6dc0189..89e3c2f8b7768 100644 --- a/drivers/block/swim_iop.c +++ b/drivers/block/swim_iop.c @@ -338,8 +338,7 @@ static int swimiop_eject(struct floppy_state *fs) err = -EINTR; break; } - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(1); } release_drive(fs); return cmd->error; diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 2c6d3423496b3..68b6d7b154cf8 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -530,10 +530,8 @@ static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long t int success; xdc_busy = 1; - while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry)) + schedule_timeout_uninterruptible(1); xdc_busy = 0; return (success); } -- GitLab From 2ddee1b7a732dc96d479afaa7d0a26aa53990089 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:29 -0700 Subject: [PATCH 422/563] [PATCH] drivers/cdrom: fix-up schedule_timeout() usage Use schedule_timeout_{un,}interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Cc: Jens Axboe <axboe@suse.de> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/cdrom/sbpcd.c | 3 +-- drivers/cdrom/sonycd535.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index 0b7d7412c4a5f..466e9c2974bdd 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -827,8 +827,7 @@ static void mark_timeout_audio(u_long i) static void sbp_sleep(u_int time) { sti(); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(time); + schedule_timeout_interruptible(time); sti(); } /*==========================================================================*/ diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c index 9f22e8f1f6c01..e656599264326 100644 --- a/drivers/cdrom/sonycd535.c +++ b/drivers/cdrom/sonycd535.c @@ -1478,8 +1478,7 @@ static int __init sony535_init(void) /* look for the CD-ROM, follows the procedure in the DOS driver */ inb(select_unit_reg); /* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout((HZ+17)*40/18); + schedule_timeout_interruptible((HZ+17)*40/18); inb(result_reg); outb(0, read_status_reg); /* does a reset? */ -- GitLab From da4cd8dfe18ee901b880f94ca0fa79d5cc1cd0eb Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:30 -0700 Subject: [PATCH 423/563] [PATCH] drivers/char: fix-up schedule_timeout() usage Use schedule_timeout_interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/char/ftape/lowlevel/fdc-io.c | 6 ++---- drivers/char/hw_random.c | 5 +---- drivers/char/ip2/i2lib.c | 6 ++---- drivers/char/ipmi/ipmi_si_intf.c | 18 ++++++------------ drivers/char/ipmi/ipmi_watchdog.c | 6 ++---- drivers/char/mxser.c | 12 ++++-------- 6 files changed, 17 insertions(+), 36 deletions(-) diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c index 1704a2a57048b..b2e0928e84288 100644 --- a/drivers/char/ftape/lowlevel/fdc-io.c +++ b/drivers/char/ftape/lowlevel/fdc-io.c @@ -387,10 +387,8 @@ int fdc_interrupt_wait(unsigned int time) set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&ftape_wait_intr, &wait); - while (!ft_interrupt_seen && timeout) { - set_current_state(TASK_INTERRUPTIBLE); - timeout = schedule_timeout(timeout); - } + while (!ft_interrupt_seen && timeout) + timeout = schedule_timeout_interruptible(timeout); spin_lock_irq(¤t->sighand->siglock); current->blocked = old_sigmask; diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c index 3480535a09c5f..6f673d2de0b17 100644 --- a/drivers/char/hw_random.c +++ b/drivers/char/hw_random.c @@ -513,10 +513,7 @@ static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, return ret ? : -EAGAIN; if(need_resched()) - { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } + schedule_timeout_interruptible(1); else udelay(200); /* FIXME: We could poll for 250uS ?? */ diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 82c5f30375acc..ba85eb1b6ec75 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -655,8 +655,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands, timeout--; // So negative values == forever if (!in_interrupt()) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); // short nap + schedule_timeout_interruptible(1); // short nap } else { // we cannot sched/sleep in interrrupt silly return 0; @@ -1132,8 +1131,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user ) ip2trace (CHANN, ITRC_OUTPUT, 61, 0 ); - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(2); + schedule_timeout_interruptible(2); if (signal_pending(current)) { break; } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 278f841049968..b6e5cbfb09f81 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1920,8 +1920,7 @@ static int try_get_dev_id(struct smi_info *smi_info) for (;;) { if (smi_result == SI_SM_CALL_WITH_DELAY) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); smi_result = smi_info->handlers->event( smi_info->si_sm, 100); } @@ -2256,10 +2255,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi) /* Wait for the timer to stop. This avoids problems with race conditions removing the timer here. */ - while (! new_smi->timer_stopped) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + while (!new_smi->timer_stopped) + schedule_timeout_uninterruptible(1); out_err: if (new_smi->intf) @@ -2379,17 +2376,14 @@ static void __exit cleanup_one_si(struct smi_info *to_clean) /* Wait for the timer to stop. This avoids problems with race conditions removing the timer here. */ - while (! to_clean->timer_stopped) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + while (!to_clean->timer_stopped) + schedule_timeout_uninterruptible(1); /* Interrupts and timeouts are stopped, now make sure the interface is in a clean state. */ while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } rv = ipmi_unregister_smi(to_clean->intf); diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index e71aaae855add..2da64bf7469c6 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -1037,10 +1037,8 @@ static __exit void ipmi_unregister_watchdog(void) /* Wait to make sure the message makes it out. The lower layer has pointers to our buffers, we want to make sure they are done before we release our memory. */ - while (atomic_read(&set_timeout_tofree)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + while (atomic_read(&set_timeout_tofree)) + schedule_timeout_uninterruptible(1); /* Disconnect from IPMI. */ rv = ipmi_destroy_user(watchdog_user); diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index d0ef1ae412981..45d012d85e8c3 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -1058,8 +1058,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) */ timeout = jiffies + HZ; while (!(inb(info->base + UART_LSR) & UART_LSR_TEMT)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(5); + schedule_timeout_interruptible(5); if (time_after(jiffies, timeout)) break; } @@ -1080,10 +1079,8 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) info->event = 0; info->tty = NULL; if (info->blocked_open) { - if (info->close_delay) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(info->close_delay); - } + if (info->close_delay) + schedule_timeout_interruptible(info->close_delay); wake_up_interruptible(&info->open_wait); } @@ -1801,8 +1798,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...", lsr, jiffies); #endif - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(char_time); + schedule_timeout_interruptible(char_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) -- GitLab From 7b4ccf8db4c1dc343ad5d6ed19240bbc3b5f945f Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:31 -0700 Subject: [PATCH 424/563] [PATCH] parport: fix-up schedule_timeout() usage Use schedule_timeout_interruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Also use human-time to jiffies units conversion functions rather than direct HZ division to avoid rounding issues. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/parport/ieee1284.c | 7 +++---- drivers/parport/ieee1284_ops.c | 10 ++++------ drivers/parport/parport_pc.c | 3 +-- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index 694bae162fed9..5b887ba5aaf9e 100644 --- a/drivers/parport/ieee1284.c +++ b/drivers/parport/ieee1284.c @@ -196,7 +196,7 @@ int parport_wait_peripheral(struct parport *port, return 1; /* 40ms of slow polling. */ - deadline = jiffies + (HZ + 24) / 25; + deadline = jiffies + msecs_to_jiffies(40); while (time_before (jiffies, deadline)) { int ret; @@ -205,7 +205,7 @@ int parport_wait_peripheral(struct parport *port, /* Wait for 10ms (or until an interrupt occurs if * the handler is set) */ - if ((ret = parport_wait_event (port, (HZ + 99) / 100)) < 0) + if ((ret = parport_wait_event (port, msecs_to_jiffies(10))) < 0) return ret; status = parport_read_status (port); @@ -216,8 +216,7 @@ int parport_wait_peripheral(struct parport *port, /* parport_wait_event didn't time out, but the * peripheral wasn't actually ready either. * Wait for another 10ms. */ - __set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout ((HZ+ 99) / 100); + schedule_timeout_interruptible(msecs_to_jiffies(10)); } } diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c index 6624278c6ed86..ce1e2aad8b100 100644 --- a/drivers/parport/ieee1284_ops.c +++ b/drivers/parport/ieee1284_ops.c @@ -60,7 +60,7 @@ size_t parport_ieee1284_write_compat (struct parport *port, parport_data_forward (port); while (count < len) { unsigned long expire = jiffies + dev->timeout; - long wait = (HZ + 99) / 100; + long wait = msecs_to_jiffies(10); unsigned char mask = (PARPORT_STATUS_ERROR | PARPORT_STATUS_BUSY); unsigned char val = (PARPORT_STATUS_ERROR @@ -97,8 +97,7 @@ size_t parport_ieee1284_write_compat (struct parport *port, our interrupt handler called. */ if (count && no_irq) { parport_release (dev); - __set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout (wait); + schedule_timeout_interruptible(wait); parport_claim_or_block (dev); } else @@ -542,13 +541,12 @@ size_t parport_ieee1284_ecp_read_data (struct parport *port, /* Yield the port for a while. */ if (count && dev->port->irq != PARPORT_IRQ_NONE) { parport_release (dev); - __set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout ((HZ + 24) / 25); + schedule_timeout_interruptible(msecs_to_jiffies(40)); parport_claim_or_block (dev); } else /* We must have the device claimed here. */ - parport_wait_event (port, (HZ + 24) / 25); + parport_wait_event (port, msecs_to_jiffies(40)); /* Is there a signal pending? */ if (signal_pending (current)) diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 1b938bb9be3cc..c6493ad7c0c86 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -173,8 +173,7 @@ static int change_mode(struct parport *p, int m) if (time_after_eq (jiffies, expire)) /* The FIFO is stuck. */ return -EBUSY; - __set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout ((HZ + 99) / 100); + schedule_timeout_interruptible(msecs_to_jiffies(10)); if (signal_pending (current)) break; } -- GitLab From 1e63bc7342c40f0f1dd83d80d368665bd06f4963 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan <nacc@us.ibm.com> Date: Sat, 10 Sep 2005 00:27:31 -0700 Subject: [PATCH 425/563] [PATCH] telephony: fix-up schedule_timeout() usage Use schedule_timeout_uninterruptible() instead of set_current_state()/schedule_timeout() to reduce kernel size. Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/telephony/ixj.c | 54 ++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index 9585d48dc4fc3..f6704688ee8c2 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -2071,8 +2071,7 @@ static int ixj_ring(IXJ *j) j->flags.ringing = 0; return 1; } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); if (signal_pending(current)) break; } @@ -2086,8 +2085,7 @@ static int ixj_ring(IXJ *j) return 1; } } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); if (signal_pending(current)) break; } @@ -2153,10 +2151,8 @@ static int ixj_release(struct inode *inode, struct file *file_p) * Set up locks to ensure that only one process is talking to the DSP at a time. * This is necessary to keep the DSP from locking up. */ - while(test_and_set_bit(board, (void *)&j->busyflags) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + while(test_and_set_bit(board, (void *)&j->busyflags) != 0) + schedule_timeout_interruptible(1); if (ixjdebug & 0x0002) printk(KERN_INFO "Closing board %d\n", NUM(inode)); @@ -3286,14 +3282,10 @@ static void ixj_write_cidcw(IXJ *j) ixj_play_tone(j, 23); clear_bit(j->board, &j->busyflags); - while(j->tone_state) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } - while(test_and_set_bit(j->board, (void *)&j->busyflags) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + while(j->tone_state) + schedule_timeout_interruptible(1); + while(test_and_set_bit(j->board, (void *)&j->busyflags) != 0) + schedule_timeout_interruptible(1); if(ixjdebug & 0x0200) { printk("IXJ cidcw phone%d first tone end at %ld\n", j->board, jiffies); } @@ -3313,14 +3305,10 @@ static void ixj_write_cidcw(IXJ *j) ixj_play_tone(j, 24); clear_bit(j->board, &j->busyflags); - while(j->tone_state) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } - while(test_and_set_bit(j->board, (void *)&j->busyflags) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + while(j->tone_state) + schedule_timeout_interruptible(1); + while(test_and_set_bit(j->board, (void *)&j->busyflags) != 0) + schedule_timeout_interruptible(1); if(ixjdebug & 0x0200) { printk("IXJ cidcw phone%d sent second tone at %ld\n", j->board, jiffies); } @@ -3328,14 +3316,10 @@ static void ixj_write_cidcw(IXJ *j) j->cidcw_wait = jiffies + ((50 * hertz) / 100); clear_bit(j->board, &j->busyflags); - while(!j->flags.cidcw_ack && time_before(jiffies, j->cidcw_wait)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } - while(test_and_set_bit(j->board, (void *)&j->busyflags) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + while(!j->flags.cidcw_ack && time_before(jiffies, j->cidcw_wait)) + schedule_timeout_interruptible(1); + while(test_and_set_bit(j->board, (void *)&j->busyflags) != 0) + schedule_timeout_interruptible(1); j->cidcw_wait = 0; if(!j->flags.cidcw_ack) { if(ixjdebug & 0x0200) { @@ -6110,10 +6094,8 @@ static int ixj_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, * Set up locks to ensure that only one process is talking to the DSP at a time. * This is necessary to keep the DSP from locking up. */ - while(test_and_set_bit(board, (void *)&j->busyflags) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + while(test_and_set_bit(board, (void *)&j->busyflags) != 0) + schedule_timeout_interruptible(1); if (ixjdebug & 0x0040) printk("phone%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg); if (minor >= IXJMAX) { -- GitLab From bb0bb3b6596cdb08adb0b72453cc67d48e139c2c Mon Sep 17 00:00:00 2001 From: Paul Mackerras <paulus@samba.org> Date: Sat, 10 Sep 2005 21:13:11 +1000 Subject: [PATCH 426/563] [PATCH] ppc32: Kill init on unhandled synchronous signals This is a patch that I have had in my tree for ages. If init causes an exception that raises a signal, such as a SIGSEGV, SIGILL or SIGFPE, and it hasn't registered a handler for it, we don't deliver the signal, since init doesn't get any signals that it doesn't have a handler for. But that means that we just return to userland and generate the same exception again immediately. With this patch we print a message and kill init in this situation. This is very useful when you have a bug in the kernel that means that init doesn't get as far as executing its first instruction. :) Without this patch the system hangs when it gets to starting the userland init; with it you at least get a message giving you a clue about what has gone wrong. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ppc/kernel/traps.c | 22 ++++++++++++++++++++++ arch/ppc/mm/fault.c | 6 +----- include/asm-ppc/system.h | 1 + 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 8356d544fa60d..961ede87be722 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -118,6 +118,28 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) info.si_code = code; info.si_addr = (void __user *) addr; force_sig_info(signr, &info, current); + + /* + * Init gets no signals that it doesn't have a handler for. + * That's all very well, but if it has caused a synchronous + * exception and we ignore the resulting signal, it will just + * generate the same exception over and over again and we get + * nowhere. Better to kill it and let the kernel panic. + */ + if (current->pid == 1) { + __sighandler_t handler; + + spin_lock_irq(¤t->sighand->siglock); + handler = current->sighand->action[signr-1].sa.sa_handler; + spin_unlock_irq(¤t->sighand->siglock); + if (handler == SIG_DFL) { + /* init has generated a synchronous exception + and it doesn't have a handler for the signal */ + printk(KERN_CRIT "init has generated signal %d " + "but has no handler for it\n", signr); + do_exit(signr); + } + } } /* diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index 57d9930843ac2..ee5e9f25baf98 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -278,11 +278,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address, /* User mode accesses cause a SIGSEGV */ if (user_mode(regs)) { - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = code; - info.si_addr = (void __user *) address; - force_sig_info(SIGSEGV, &info, current); + _exception(SIGSEGV, regs, code, address); return 0; } diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 513a334c58103..d754ab570fe0e 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -88,6 +88,7 @@ extern void *cacheable_memcpy(void *, const void *, unsigned int); extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long); extern void bad_page_fault(struct pt_regs *, unsigned long, int); extern void die(const char *, struct pt_regs *, long); +extern void _exception(int, struct pt_regs *, int, unsigned long); #ifdef CONFIG_BOOKE_WDT extern u32 booke_wdt_enabled; extern u32 booke_wdt_period; -- GitLab From 31139971b3dc9fbb2e8a8572fb81e6e8470f363a Mon Sep 17 00:00:00 2001 From: Paul Mackerras <paulus@samba.org> Date: Sat, 10 Sep 2005 21:13:13 +1000 Subject: [PATCH 427/563] [PATCH] ppc32: support hotplug cpu on powermacs This allows cpus to be off-lined on 32-bit SMP powermacs. When a cpu is off-lined, it is put into sleep mode with interrupts disabled. It can be on-lined again by asserting its soft-reset pin, which is connected to a GPIO pin. With this I can off-line the second cpu in my dual G4 powermac, which means that I can then suspend the machine (the suspend/resume code refuses to suspend if more than one cpu is online, and making it cope with multiple cpus is surprisingly messy). Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ppc/Kconfig | 9 ++++ arch/ppc/kernel/head.S | 28 +++++------ arch/ppc/kernel/idle.c | 6 ++- arch/ppc/kernel/smp.c | 44 +++++++++++------ arch/ppc/platforms/pmac_sleep.S | 2 + arch/ppc/platforms/pmac_smp.c | 85 +++++++++++++++++++++------------ include/asm-ppc/smp.h | 6 +++ 7 files changed, 119 insertions(+), 61 deletions(-) diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index e3f1ce33e6425..347ea284140b2 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -265,6 +265,15 @@ config PPC601_SYNC_FIX If in doubt, say Y here. +config HOTPLUG_CPU + bool "Support for enabling/disabling CPUs" + depends on SMP && HOTPLUG && EXPERIMENTAL && PPC_PMAC + ---help--- + Say Y here to be able to disable and re-enable individual + CPUs at runtime on SMP machines. + + Say N if you are unsure. + source arch/ppc/platforms/4xx/Kconfig source arch/ppc/platforms/85xx/Kconfig diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 55daf1210f322..1960fb8c259c6 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1023,23 +1023,21 @@ __secondary_start_gemini: andc r4,r4,r3 mtspr SPRN_HID0,r4 sync - bl gemini_prom_init b __secondary_start #endif /* CONFIG_GEMINI */ - .globl __secondary_start_psurge -__secondary_start_psurge: - li r24,1 /* cpu # */ - b __secondary_start_psurge99 - .globl __secondary_start_psurge2 -__secondary_start_psurge2: - li r24,2 /* cpu # */ - b __secondary_start_psurge99 - .globl __secondary_start_psurge3 -__secondary_start_psurge3: - li r24,3 /* cpu # */ - b __secondary_start_psurge99 -__secondary_start_psurge99: - /* we come in here with IR=0 and DR=1, and DBAT 0 + + .globl __secondary_start_pmac_0 +__secondary_start_pmac_0: + /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */ + li r24,0 + b 1f + li r24,1 + b 1f + li r24,2 + b 1f + li r24,3 +1: + /* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0 set to map the 0xf0000000 - 0xffffffff region */ mfmsr r0 rlwinm r0,r0,0,28,26 /* clear DR (0x10) */ diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index 53547b6de45bd..fba29c876b62a 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -22,6 +22,7 @@ #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/sysctl.h> +#include <linux/cpu.h> #include <asm/pgtable.h> #include <asm/uaccess.h> @@ -35,6 +36,7 @@ void default_idle(void) { void (*powersave)(void); + int cpu = smp_processor_id(); powersave = ppc_md.power_save; @@ -44,7 +46,7 @@ void default_idle(void) #ifdef CONFIG_SMP else { set_thread_flag(TIF_POLLING_NRFLAG); - while (!need_resched()) + while (!need_resched() && !cpu_is_offline(cpu)) barrier(); clear_thread_flag(TIF_POLLING_NRFLAG); } @@ -52,6 +54,8 @@ void default_idle(void) } if (need_resched()) schedule(); + if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) + cpu_die(); } /* diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index e70b587b9e514..726fe7ce1747a 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -45,6 +45,7 @@ cpumask_t cpu_online_map; cpumask_t cpu_possible_map; int smp_hw_index[NR_CPUS]; struct thread_info *secondary_ti; +static struct task_struct *idle_tasks[NR_CPUS]; EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(cpu_possible_map); @@ -286,7 +287,8 @@ static void __devinit smp_store_cpu_info(int id) void __init smp_prepare_cpus(unsigned int max_cpus) { - int num_cpus, i; + int num_cpus, i, cpu; + struct task_struct *p; /* Fixup boot cpu */ smp_store_cpu_info(smp_processor_id()); @@ -308,6 +310,17 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (smp_ops->space_timers) smp_ops->space_timers(num_cpus); + + for_each_cpu(cpu) { + if (cpu == smp_processor_id()) + continue; + /* create a process for the processor */ + p = fork_idle(cpu); + if (IS_ERR(p)) + panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); + p->thread_info->cpu = cpu; + idle_tasks[cpu] = p; + } } void __devinit smp_prepare_boot_cpu(void) @@ -334,12 +347,17 @@ int __devinit start_secondary(void *unused) set_dec(tb_ticks_per_jiffy); cpu_callin_map[cpu] = 1; - printk("CPU %i done callin...\n", cpu); + printk("CPU %d done callin...\n", cpu); smp_ops->setup_cpu(cpu); - printk("CPU %i done setup...\n", cpu); - local_irq_enable(); + printk("CPU %d done setup...\n", cpu); smp_ops->take_timebase(); - printk("CPU %i done timebase take...\n", cpu); + printk("CPU %d done timebase take...\n", cpu); + + spin_lock(&call_lock); + cpu_set(cpu, cpu_online_map); + spin_unlock(&call_lock); + + local_irq_enable(); cpu_idle(); return 0; @@ -347,17 +365,11 @@ int __devinit start_secondary(void *unused) int __cpu_up(unsigned int cpu) { - struct task_struct *p; char buf[32]; int c; - /* create a process for the processor */ - /* only regs.msr is actually used, and 0 is OK for it */ - p = fork_idle(cpu); - if (IS_ERR(p)) - panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); - secondary_ti = p->thread_info; - p->thread_info->cpu = cpu; + secondary_ti = idle_tasks[cpu]->thread_info; + mb(); /* * There was a cache flush loop here to flush the cache @@ -389,7 +401,11 @@ int __cpu_up(unsigned int cpu) printk("Processor %d found.\n", cpu); smp_ops->give_timebase(); - cpu_set(cpu, cpu_online_map); + + /* Wait until cpu puts itself in the online map */ + while (!cpu_online(cpu)) + cpu_relax(); + return 0; } diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S index 8d67adc769258..88419c77ac439 100644 --- a/arch/ppc/platforms/pmac_sleep.S +++ b/arch/ppc/platforms/pmac_sleep.S @@ -161,6 +161,8 @@ _GLOBAL(low_sleep_handler) addi r3,r3,sleep_storage@l stw r5,0(r3) + .globl low_cpu_die +low_cpu_die: /* Flush & disable all caches */ bl flush_disable_caches diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c index 8e049dab4e632..794a23994b82a 100644 --- a/arch/ppc/platforms/pmac_smp.c +++ b/arch/ppc/platforms/pmac_smp.c @@ -33,6 +33,7 @@ #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/hardirq.h> +#include <linux/cpu.h> #include <asm/ptrace.h> #include <asm/atomic.h> @@ -55,9 +56,7 @@ * Powersurge (old powermac SMP) support. */ -extern void __secondary_start_psurge(void); -extern void __secondary_start_psurge2(void); /* Temporary horrible hack */ -extern void __secondary_start_psurge3(void); /* Temporary horrible hack */ +extern void __secondary_start_pmac_0(void); /* Addresses for powersurge registers */ #define HAMMERHEAD_BASE 0xf8000000 @@ -119,7 +118,7 @@ static volatile int sec_tb_reset = 0; static unsigned int pri_tb_hi, pri_tb_lo; static unsigned int pri_tb_stamp; -static void __init core99_init_caches(int cpu) +static void __devinit core99_init_caches(int cpu) { if (!cpu_has_feature(CPU_FTR_L2CR)) return; @@ -346,7 +345,7 @@ static int __init smp_psurge_probe(void) static void __init smp_psurge_kick_cpu(int nr) { - void (*start)(void) = __secondary_start_psurge; + unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8; unsigned long a; /* may need to flush here if secondary bats aren't setup */ @@ -356,17 +355,7 @@ static void __init smp_psurge_kick_cpu(int nr) if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353); - /* setup entry point of secondary processor */ - switch (nr) { - case 2: - start = __secondary_start_psurge2; - break; - case 3: - start = __secondary_start_psurge3; - break; - } - - out_be32(psurge_start, __pa(start)); + out_be32(psurge_start, start); mb(); psurge_set_ipi(nr); @@ -500,14 +489,14 @@ static int __init smp_core99_probe(void) return ncpus; } -static void __init smp_core99_kick_cpu(int nr) +static void __devinit smp_core99_kick_cpu(int nr) { unsigned long save_vector, new_vector; unsigned long flags; volatile unsigned long *vector = ((volatile unsigned long *)(KERNELBASE+0x100)); - if (nr < 1 || nr > 3) + if (nr < 0 || nr > 3) return; if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); @@ -518,19 +507,9 @@ static void __init smp_core99_kick_cpu(int nr) save_vector = *vector; /* Setup fake reset vector that does - * b __secondary_start_psurge - KERNELBASE + * b __secondary_start_pmac_0 + nr*8 - KERNELBASE */ - switch(nr) { - case 1: - new_vector = (unsigned long)__secondary_start_psurge; - break; - case 2: - new_vector = (unsigned long)__secondary_start_psurge2; - break; - case 3: - new_vector = (unsigned long)__secondary_start_psurge3; - break; - } + new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8; *vector = 0x48000002 + new_vector - KERNELBASE; /* flush data cache and inval instruction cache */ @@ -554,7 +533,7 @@ static void __init smp_core99_kick_cpu(int nr) if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); } -static void __init smp_core99_setup_cpu(int cpu_nr) +static void __devinit smp_core99_setup_cpu(int cpu_nr) { /* Setup L2/L3 */ if (cpu_nr != 0) @@ -668,3 +647,47 @@ struct smp_ops_t core99_smp_ops __pmacdata = { .give_timebase = smp_core99_give_timebase, .take_timebase = smp_core99_take_timebase, }; + +#ifdef CONFIG_HOTPLUG_CPU + +int __cpu_disable(void) +{ + cpu_clear(smp_processor_id(), cpu_online_map); + + /* XXX reset cpu affinity here */ + openpic_set_priority(0xf); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + mb(); + udelay(20); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + return 0; +} + +extern void low_cpu_die(void) __attribute__((noreturn)); /* in pmac_sleep.S */ +static int cpu_dead[NR_CPUS]; + +void cpu_die(void) +{ + local_irq_disable(); + cpu_dead[smp_processor_id()] = 1; + mb(); + low_cpu_die(); +} + +void __cpu_die(unsigned int cpu) +{ + int timeout; + + timeout = 1000; + while (!cpu_dead[cpu]) { + if (--timeout == 0) { + printk("CPU %u refused to die!\n", cpu); + break; + } + msleep(1); + } + cpu_callin_map[cpu] = 0; + cpu_dead[cpu] = 0; +} + +#endif diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h index 17530c232c769..829481c0a9dc2 100644 --- a/include/asm-ppc/smp.h +++ b/include/asm-ppc/smp.h @@ -41,6 +41,10 @@ extern void smp_send_xmon_break(int cpu); struct pt_regs; extern void smp_message_recv(int, struct pt_regs *); +extern int __cpu_disable(void); +extern void __cpu_die(unsigned int cpu); +extern void cpu_die(void) __attribute__((noreturn)); + #define NO_PROC_ID 0xFF /* No processor magic marker */ #define PROC_CHANGE_PENALTY 20 @@ -64,6 +68,8 @@ extern struct klock_info_struct klock_info; #else /* !(CONFIG_SMP) */ +static inline void cpu_die(void) { } + #endif /* !(CONFIG_SMP) */ #endif /* !(_PPC_SMP_H) */ -- GitLab From 35797132b311b3b7d4add48393b0a03f3566cbc1 Mon Sep 17 00:00:00 2001 From: Jens Axboe <axboe@suse.de> Date: Sat, 10 Sep 2005 14:17:10 +0200 Subject: [PATCH 428/563] [PATCH] cfq-iosched: reverse bad reference count fix The reference count fix merged isn't fully bug free. It doesn't leak now, but instead it crashes due to looking at freed memory. So for now, lets reverse the change and I'll fix it for real next week. Signed-off-by: Jens Axboe <axboe@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/block/cfq-iosched.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index 30c0903c7cddf..cd056e7e64ec1 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -2260,6 +2260,8 @@ static void cfq_put_cfqd(struct cfq_data *cfqd) if (!atomic_dec_and_test(&cfqd->ref)) return; + blk_put_queue(q); + cfq_shutdown_timer_wq(cfqd); q->elevator->elevator_data = NULL; @@ -2316,6 +2318,7 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e) e->elevator_data = cfqd; cfqd->queue = q; + atomic_inc(&q->refcnt); cfqd->max_queued = q->nr_requests / 4; q->nr_batching = cfq_queued; -- GitLab From b35b7072178b76814a088ac71ac4702de8bf7c7b Mon Sep 17 00:00:00 2001 From: Stephen Rothwell <sfr@canb.auug.org.au> Date: Sun, 11 Sep 2005 00:00:14 +1000 Subject: [PATCH 429/563] [PATCH] powerpc: Move include3 to arch/$(ARCH)/include This is less troublesome and makes more sense. Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ppc/Makefile | 16 +++++++++------- arch/ppc64/Makefile | 13 +++++++------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 4b3fe395ffa4d..6dd7b50e06691 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -21,13 +21,14 @@ CC := $(CC) -m32 endif LDFLAGS_vmlinux := -Ttext $(KERNELLOAD) -Bstatic -CPPFLAGS += -Iarch/$(ARCH) -Iinclude3 +# The -Iarch/$(ARCH)/include is temporary while we are merging +CPPFLAGS += -Iarch/$(ARCH) -Iarch/$(ARCH)/include AFLAGS += -Iarch/$(ARCH) CFLAGS += -Iarch/$(ARCH) -msoft-float -pipe \ -ffixed-r2 -mmultiple CPP = $(CC) -E $(CFLAGS) # Temporary hack until we have migrated to asm-powerpc -LINUXINCLUDE += -Iinclude3 +LINUXINCLUDE += -Iarch/$(ARCH)/include CHECKFLAGS += -D__powerpc__ @@ -103,15 +104,16 @@ endef archclean: $(Q)$(MAKE) $(clean)=arch/ppc/boot - $(Q)rm -rf include3 + # Temporary hack until we have migrated to asm-powerpc + $(Q)rm -rf arch/$(ARCH)/include prepare: checkbin # Temporary hack until we have migrated to asm-powerpc -include/asm: include3/asm -include3/asm: - $(Q)if [ ! -d include3 ]; then mkdir -p include3; fi - $(Q)ln -fsn $(srctree)/include/asm-powerpc include3/asm +include/asm: arch/$(ARCH)/include/asm +arch/$(ARCH)/include/asm: + $(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi + $(Q)ln -fsn $(srctree)/include/asm-powerpc arch/$(ARCH)/include/asm # Use the file '.tmp_gas_check' for binutils tests, as gas won't output # to stdout and these checks are run even on install targets. diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 0a23aeacba885..17d2c1eac3b85 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -56,7 +56,7 @@ LDFLAGS_vmlinux := -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD) CFLAGS += -msoft-float -pipe -mminimal-toc -mtraceback=none \ -mcall-aixdesc # Temporary hack until we have migrated to asm-powerpc -CPPFLAGS += -Iinclude3 +CPPFLAGS += -Iarch/$(ARCH)/include GCC_VERSION := $(call cc-version) GCC_BROKEN_VEC := $(shell if [ $(GCC_VERSION) -lt 0400 ] ; then echo "y"; fi ;) @@ -115,14 +115,15 @@ all: $(KBUILD_IMAGE) archclean: $(Q)$(MAKE) $(clean)=$(boot) - $(Q)rm -rf include3 + # Temporary hack until we have migrated to asm-powerpc + $(Q)rm -rf arch/$(ARCH)/include # Temporary hack until we have migrated to asm-powerpc -include/asm: include3/asm -include3/asm: - $(Q)if [ ! -d include3 ]; then mkdir -p include3; fi; - $(Q)ln -fsn $(srctree)/include/asm-powerpc include3/asm +include/asm: arch/$(ARCH)/include/asm +arch/$(ARCH)/include/asm: + $(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi + $(Q)ln -fsn $(srctree)/include/asm-powerpc arch/$(ARCH)/include/asm define archhelp echo ' zImage.vmode - Compressed kernel image (arch/$(ARCH)/boot/zImage.vmode)' -- GitLab From fe08ac3178243fbed61f24878ffcf5cfb53fceb1 Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" <viro@ZenIV.linux.org.uk> Date: Fri, 9 Sep 2005 22:03:44 +0100 Subject: [PATCH 430/563] [PATCH] __user annotations (scsi/ch) Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/scsi/ch.c | 27 ++++++++++++++------------- include/linux/chio.h | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 13ecd0c474043..da6e51c7fe696 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -560,7 +560,7 @@ ch_set_voltag(scsi_changer *ch, u_int elem, return result; } -static int ch_gstatus(scsi_changer *ch, int type, unsigned char *dest) +static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest) { int retval = 0; u_char data[16]; @@ -634,6 +634,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, { scsi_changer *ch = file->private_data; int retval; + void __user *argp = (void __user *)arg; switch (cmd) { case CHIOGPARAMS: @@ -646,7 +647,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, params.cp_nportals = ch->counts[CHET_IE]; params.cp_ndrives = ch->counts[CHET_DT]; - if (copy_to_user((void *) arg, ¶ms, sizeof(params))) + if (copy_to_user(argp, ¶ms, sizeof(params))) return -EFAULT; return 0; } @@ -671,7 +672,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, vparams.cvp_n4 = ch->counts[CHET_V4]; strncpy(vparams.cvp_label4,vendor_labels[3],16); } - if (copy_to_user((void *) arg, &vparams, sizeof(vparams))) + if (copy_to_user(argp, &vparams, sizeof(vparams))) return -EFAULT; return 0; } @@ -680,7 +681,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, { struct changer_position pos; - if (copy_from_user(&pos, (void*)arg, sizeof (pos))) + if (copy_from_user(&pos, argp, sizeof (pos))) return -EFAULT; if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) { @@ -699,7 +700,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, { struct changer_move mv; - if (copy_from_user(&mv, (void*)arg, sizeof (mv))) + if (copy_from_user(&mv, argp, sizeof (mv))) return -EFAULT; if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) || @@ -721,7 +722,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, { struct changer_exchange mv; - if (copy_from_user(&mv, (void*)arg, sizeof (mv))) + if (copy_from_user(&mv, argp, sizeof (mv))) return -EFAULT; if (0 != ch_checkrange(ch, mv.ce_srctype, mv.ce_srcunit ) || @@ -746,7 +747,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, { struct changer_element_status ces; - if (copy_from_user(&ces, (void*)arg, sizeof (ces))) + if (copy_from_user(&ces, argp, sizeof (ces))) return -EFAULT; if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES) return -EINVAL; @@ -762,7 +763,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, unsigned int elem; int result,i; - if (copy_from_user(&cge, (void*)arg, sizeof (cge))) + if (copy_from_user(&cge, argp, sizeof (cge))) return -EFAULT; if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit)) @@ -825,7 +826,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, kfree(buffer); up(&ch->lock); - if (copy_to_user((void*)arg, &cge, sizeof (cge))) + if (copy_to_user(argp, &cge, sizeof (cge))) return -EFAULT; return result; } @@ -843,7 +844,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, struct changer_set_voltag csv; int elem; - if (copy_from_user(&csv, (void*)arg, sizeof(csv))) + if (copy_from_user(&csv, argp, sizeof(csv))) return -EFAULT; if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) { @@ -861,7 +862,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, } default: - return scsi_ioctl(ch->device, cmd, (void*)arg); + return scsi_ioctl(ch->device, cmd, argp); } } @@ -894,9 +895,9 @@ static long ch_ioctl_compat(struct file * file, case CHIOGSTATUS32: { struct changer_element_status32 ces32; - unsigned char *data; + unsigned char __user *data; - if (copy_from_user(&ces32, (void*)arg, sizeof (ces32))) + if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32))) return -EFAULT; if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES) return -EINVAL; diff --git a/include/linux/chio.h b/include/linux/chio.h index 63035ae67e635..a404c111c937a 100644 --- a/include/linux/chio.h +++ b/include/linux/chio.h @@ -96,7 +96,7 @@ struct changer_position { */ struct changer_element_status { int ces_type; - unsigned char *ces_data; + unsigned char __user *ces_data; }; #define CESTATUS_FULL 0x01 /* full */ #define CESTATUS_IMPEXP 0x02 /* media was imported (inserted by sysop) */ -- GitLab From 0aaaa028297a0e2aed9671419a11d8e17510cb51 Mon Sep 17 00:00:00 2001 From: "viro@ZenIV.linux.org.uk" <viro@ZenIV.linux.org.uk> Date: Fri, 9 Sep 2005 22:09:08 +0100 Subject: [PATCH 431/563] [PATCH] envctrl fixes envctrl doesn't need unistd.h; moreover, since it declares errno static gcc4 gets very unhappy about including unistd.h. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/sbus/char/bbc_envctrl.c | 3 +-- drivers/sbus/char/envctrl.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index d44205d52bf3c..d89f83f769f54 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -5,6 +5,7 @@ */ #define __KERNEL_SYSCALLS__ +static int errno; #include <linux/kernel.h> #include <linux/kthread.h> @@ -13,8 +14,6 @@ #include <linux/delay.h> #include <asm/oplib.h> #include <asm/ebus.h> -static int errno; -#include <asm/unistd.h> #include "bbc_i2c.h" #include "max1617.h" diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index d765cc1bf060b..b0cc3c2588fdd 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -20,6 +20,7 @@ */ #define __KERNEL_SYSCALLS__ +static int errno; #include <linux/config.h> #include <linux/module.h> @@ -38,9 +39,6 @@ #include <asm/uaccess.h> #include <asm/envctrl.h> -static int errno; -#include <asm/unistd.h> - #define ENVCTRL_MINOR 162 #define PCF8584_ADDRESS 0x55 -- GitLab From 2d5cbf324c0fd4d0e1427bcb50b8bc00069e81b8 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Date: Sat, 10 Sep 2005 19:44:53 +0200 Subject: [PATCH 432/563] [PATCH] Uml: more cleaning We must remove even arch/um/os-Linux/util/mk_user_constants, which we don't do. Also, Kconfig_arch must be listed only once, between CLEAN_FILES. Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/um/Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/um/Makefile b/arch/um/Makefile index 577b8d1cf1a6e..154803a226984 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -103,7 +103,6 @@ endef ifneq ($(KBUILD_SRC),) $(shell mkdir -p $(ARCH_DIR) && ln -fsn $(srctree)/$(ARCH_DIR)/Kconfig.$(SUBARCH) $(ARCH_DIR)/Kconfig.arch) -CLEAN_FILES += $(ARCH_DIR)/Kconfig.arch else $(shell cd $(ARCH_DIR) && ln -sf Kconfig.$(SUBARCH) Kconfig.arch) endif @@ -144,14 +143,14 @@ endef #TT or skas makefiles and don't clean skas_ptregs.h. CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \ $(GEN_HEADERS) $(ARCH_DIR)/include/skas_ptregs.h \ - $(ARCH_DIR)/include/user_constants.h + $(ARCH_DIR)/include/user_constants.h $(ARCH_DIR)/Kconfig.arch MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ - $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os \ - $(ARCH_DIR)/Kconfig.arch + $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os archclean: $(Q)$(MAKE) $(clean)=$(ARCH_DIR)/util + $(Q)$(MAKE) $(clean)=$(ARCH_DIR)/os-$(OS)/util @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ -o -name '*.gcov' \) -type f -print | xargs rm -f -- GitLab From a7d0c210337246fa9c25b73cf76dfdbb159f642b Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Date: Sat, 10 Sep 2005 19:44:54 +0200 Subject: [PATCH 433/563] [PATCH] i386 / uml: add dwarf sections to static link script Inside the linker script, insert the code for DWARF debug info sections. This may help GDB'ing a Uml binary. Actually, it seems that ld is able to guess what I added correctly, but normal linker scripts include this section so it should be correct anyway adding it. On request by Sam Ravnborg <sam@ravnborg.org>, I've added it to asm-generic/vmlinux.lds.s. I've also moved there the stabs debug section, used the new macro in i386 linker script and added DWARF debug section to that. In the truth, I've not been able to verify the difference in GDB behaviour after this change (I've seen large improvements with another patch). This may depend on my binutils version, older one may have worse defaults. However, this section is present in normal linker script, so add it at least for the sake of cleanness. Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Acked-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/kernel/vmlinux.lds.S | 11 +++------ arch/um/kernel/dyn.lds.S | 37 ++++-------------------------- arch/um/kernel/uml.lds.S | 14 ++++-------- include/asm-generic/vmlinux.lds.h | 38 +++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S index 13b9c62cbbb45..4710195b6b748 100644 --- a/arch/i386/kernel/vmlinux.lds.S +++ b/arch/i386/kernel/vmlinux.lds.S @@ -144,12 +144,7 @@ SECTIONS *(.exitcall.exit) } - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } + STABS_DEBUG + + DWARF_DEBUG } diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index 3942a5f245de6..2517ecb8bf27d 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -146,37 +146,8 @@ SECTIONS } _end = .; PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } + + STABS_DEBUG + + DWARF_DEBUG } diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index b03326d391c92..af11915ce0a8c 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -93,14 +93,10 @@ SECTIONS *(.bss) *(COMMON) } - _end = . ; + _end = .; PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } + + STABS_DEBUG + + DWARF_DEBUG } diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 6f857be2b6447..a9c55490fb823 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -103,3 +103,41 @@ VMLINUX_SYMBOL(__kprobes_text_start) = .; \ *(.kprobes.text) \ VMLINUX_SYMBOL(__kprobes_text_end) = .; + + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to + the beginning of the section so we begin them at 0. */ +#define DWARF_DEBUG \ + /* DWARF 1 */ \ + .debug 0 : { *(.debug) } \ + .line 0 : { *(.line) } \ + /* GNU DWARF 1 extensions */ \ + .debug_srcinfo 0 : { *(.debug_srcinfo) } \ + .debug_sfnames 0 : { *(.debug_sfnames) } \ + /* DWARF 1.1 and DWARF 2 */ \ + .debug_aranges 0 : { *(.debug_aranges) } \ + .debug_pubnames 0 : { *(.debug_pubnames) } \ + /* DWARF 2 */ \ + .debug_info 0 : { *(.debug_info \ + .gnu.linkonce.wi.*) } \ + .debug_abbrev 0 : { *(.debug_abbrev) } \ + .debug_line 0 : { *(.debug_line) } \ + .debug_frame 0 : { *(.debug_frame) } \ + .debug_str 0 : { *(.debug_str) } \ + .debug_loc 0 : { *(.debug_loc) } \ + .debug_macinfo 0 : { *(.debug_macinfo) } \ + /* SGI/MIPS DWARF 2 extensions */ \ + .debug_weaknames 0 : { *(.debug_weaknames) } \ + .debug_funcnames 0 : { *(.debug_funcnames) } \ + .debug_typenames 0 : { *(.debug_typenames) } \ + .debug_varnames 0 : { *(.debug_varnames) } \ + + /* Stabs debugging sections. */ +#define STABS_DEBUG \ + .stab 0 : { *(.stab) } \ + .stabstr 0 : { *(.stabstr) } \ + .stab.excl 0 : { *(.stab.excl) } \ + .stab.exclstr 0 : { *(.stab.exclstr) } \ + .stab.index 0 : { *(.stab.index) } \ + .stab.indexstr 0 : { *(.stab.indexstr) } \ + .comment 0 : { *(.comment) } -- GitLab From 4413a511f22ec771edc0b7c93e5b34e05511acb5 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Date: Sat, 10 Sep 2005 19:44:55 +0200 Subject: [PATCH 434/563] [PATCH] x86_64 linker script cleanups for debug sections Use the new macros for x86_64 too. Note that the current scripts includes different definitions; more exactly, it only contains part of the DWARF2 sections and the .comment one from Stabs. Shouldn't be a problem, anyway. Cc: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/vmlinux.lds.S | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S index d4abb07af52db..6dd642cad2efd 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S @@ -194,20 +194,7 @@ SECTIONS #endif } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - - .comment 0 : { *(.comment) } + STABS_DEBUG + + DWARF_DEBUG } -- GitLab From d99c4022f60a9aa3a8dc6b7d71f3d0998c696912 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Date: Sat, 10 Sep 2005 19:44:56 +0200 Subject: [PATCH 435/563] [PATCH] uml: inline mk_pte and various friends Turns out that, for UML, a *lot* of VM-related trivial functions are not inlined but rather normal functions. In other sections of UML code, this is justified by having files which interact with the host and cannot therefore include kernel headers, but in this case there's no such justification. I've had to turn many of them to macros because of missing declarations. While doing this, I've decided to reuse some already existing macros. Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/um/include/mem.h | 12 +++++++++++- arch/um/kernel/ksyms.c | 5 ----- arch/um/kernel/physmem.c | 35 ----------------------------------- include/asm-um/page.h | 3 +-- include/asm-um/pgtable.h | 16 +++++++++++----- 5 files changed, 23 insertions(+), 48 deletions(-) diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h index 99d3ad4a03e5a..e8ff0d8fa6103 100644 --- a/arch/um/include/mem.h +++ b/arch/um/include/mem.h @@ -13,7 +13,17 @@ extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w); extern int is_remapped(void *virt); extern int physmem_remove_mapping(void *virt); extern void physmem_forget_descriptor(int fd); -extern unsigned long to_phys(void *virt); + +extern unsigned long uml_physmem; +static inline unsigned long to_phys(void *virt) +{ + return(((unsigned long) virt) - uml_physmem); +} + +static inline void *to_virt(unsigned long phys) +{ + return((void *) uml_physmem + phys); +} #endif diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 32d3076dd2204..a97a72e516aa6 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -34,14 +34,9 @@ EXPORT_SYMBOL(host_task_size); EXPORT_SYMBOL(arch_validate); EXPORT_SYMBOL(get_kmem_end); -EXPORT_SYMBOL(page_to_phys); -EXPORT_SYMBOL(phys_to_page); EXPORT_SYMBOL(high_physmem); EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(um_virt_to_phys); -EXPORT_SYMBOL(__virt_to_page); -EXPORT_SYMBOL(to_phys); -EXPORT_SYMBOL(to_virt); EXPORT_SYMBOL(mode_tt); EXPORT_SYMBOL(handle_page_fault); EXPORT_SYMBOL(find_iomem); diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index a24e3b7f4bf07..ea670fcc8af5b 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -248,16 +248,6 @@ unsigned long high_physmem; extern unsigned long physmem_size; -void *to_virt(unsigned long phys) -{ - return((void *) uml_physmem + phys); -} - -unsigned long to_phys(void *virt) -{ - return(((unsigned long) virt) - uml_physmem); -} - int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) { struct page *p, *map; @@ -298,31 +288,6 @@ int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) return(0); } -struct page *phys_to_page(const unsigned long phys) -{ - return(&mem_map[phys >> PAGE_SHIFT]); -} - -struct page *__virt_to_page(const unsigned long virt) -{ - return(&mem_map[__pa(virt) >> PAGE_SHIFT]); -} - -phys_t page_to_phys(struct page *page) -{ - return((page - mem_map) << PAGE_SHIFT); -} - -pte_t mk_pte(struct page *page, pgprot_t pgprot) -{ - pte_t pte; - - pte_set_val(pte, page_to_phys(page), pgprot); - if(pte_present(pte)) - pte_mknewprot(pte_mknewpage(pte)); - return(pte); -} - /* Changed during early boot */ static unsigned long kmem_top = 0; diff --git a/include/asm-um/page.h b/include/asm-um/page.h index bd850a249183d..2c192abe9aeb0 100644 --- a/include/asm-um/page.h +++ b/include/asm-um/page.h @@ -96,8 +96,7 @@ extern unsigned long uml_physmem; #define __va_space (8*1024*1024) -extern unsigned long to_phys(void *virt); -extern void *to_virt(unsigned long phys); +#include "mem.h" /* Cast to unsigned long before casting to void * to avoid a warning from * mmap_kmem about cutting a long long down to a void *. Not sure that diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h index b48e0966ecd7b..ed06170e0eddd 100644 --- a/include/asm-um/pgtable.h +++ b/include/asm-um/pgtable.h @@ -326,14 +326,22 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval) } #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) -extern phys_t page_to_phys(struct page *page); - /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ -extern pte_t mk_pte(struct page *page, pgprot_t pgprot); +#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys)) +#define __virt_to_page(virt) phys_to_page(__pa(virt)) +#define page_to_phys(page) pfn_to_phys(page_to_pfn(page)) + +#define mk_pte(page, pgprot) \ + ({ pte_t pte; \ + \ + pte_set_val(pte, page_to_phys(page), (pgprot)); \ + if (pte_present(pte)) \ + pte_mknewprot(pte_mknewpage(pte)); \ + pte;}) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { @@ -410,8 +418,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #endif #endif -extern struct page *phys_to_page(const unsigned long phys); -extern struct page *__virt_to_page(const unsigned long virt); #define virt_to_page(addr) __virt_to_page((const unsigned long) addr) /* -- GitLab From d129f31236c241c07e583e8bc695c382365d02ce Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Date: Sat, 10 Sep 2005 19:44:57 +0200 Subject: [PATCH 436/563] [PATCH] uml: fix fault handler on write The UML fault handler was recently changed to enforce PROT_NONE protections, by requiring VM_READ or VM_EXEC on VMA's. However, by mistake, things were changed such that VM_READ is always checked, also on write faults; so a VMA mapped with only PROT_WRITE is not readable (unless it's prefaulted with MAP_POPULATE or with a write), which is different from i386. Discovered while testing remap_file_pages protection support. Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/um/kernel/trap_kern.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index b5fc89fe9eab8..d20361dcd1274 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -57,7 +57,8 @@ int handle_page_fault(unsigned long address, unsigned long ip, if(is_write && !(vma->vm_flags & VM_WRITE)) goto out; - if(!(vma->vm_flags & (VM_READ | VM_EXEC))) + /* Don't require VM_READ|VM_EXEC for write faults! */ + if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC))) goto out; do { -- GitLab From 16b036786a6bd08cf7a91e0cd58219a6717da2a6 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Date: Sat, 10 Sep 2005 19:44:58 +0200 Subject: [PATCH 437/563] [PATCH] uml: avoid already done dirtying The PTE returned from handle_mm_fault is already marked as dirty and accessed if needed. Also, since this is not set with set_pte() (which sets NEWPAGE and NEWPROT as needed), this wouldn't work anyway. This version has been updated and fixed, thanks to some feedback from Jeff Dike. Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/um/kernel/trap_kern.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index d20361dcd1274..87cc6fd76cede 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -85,8 +85,7 @@ int handle_page_fault(unsigned long address, unsigned long ip, pte = pte_offset_kernel(pmd, address); } while(!pte_present(*pte)); err = 0; - *pte = pte_mkyoung(*pte); - if(pte_write(*pte)) *pte = pte_mkdirty(*pte); + WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte))); flush_tlb_page(vma, address); out: up_read(&mm->mmap_sem); -- GitLab From 0a504f259c90fb41d3495d490fc9dbe2530c8749 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.ravnborg.org> Date: Sat, 10 Sep 2005 21:02:11 +0200 Subject: [PATCH 438/563] kbuild: add objectify Use foo := $(call objectify, $(foo)) to prefix $(foo) with $(obj)/ unless $(foo) is an absolute path. For now no in-tree users - soon to come. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- scripts/Kbuild.include | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 9087273abf916..db3c708e546b8 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -49,6 +49,9 @@ build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj cmd = @$(if $($(quiet)cmd_$(1)),\ echo ' $(subst ','\'',$($(quiet)cmd_$(1)))' &&) $(cmd_$(1)) +# Add $(obj)/ for paths that is not absolute +objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o))) + ### # if_changed - execute command if any prerequisite is newer than # target, or command line has changed -- GitLab From 8d36a62364b6b04dc7b0e9fe09f6968f4e5a1f0a Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.ravnborg.org> Date: Sat, 10 Sep 2005 21:05:36 +0200 Subject: [PATCH 439/563] kbuild: fix generic asm-offsets.h support iThis fixes a bug where the generated asm-offsets.h file was saved in the source tree even with make O=. Thanks to Stephen Rothwell <sfr@canb.auug.org.au> for the report. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- Kbuild | 5 +++-- Makefile | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Kbuild b/Kbuild index 1880e6f760aab..79003918f37f2 100644 --- a/Kbuild +++ b/Kbuild @@ -4,7 +4,7 @@ # 1) Generate asm-offsets.h ##### -# 1) Generate asm-offsets.h +# 1) Generate asm-offsets.h # offsets-file := include/asm-$(ARCH)/asm-offsets.h @@ -22,6 +22,7 @@ sed-$(CONFIG_MIPS) := "/^@@@/s///p" quiet_cmd_offsets = GEN $@ define cmd_offsets + mkdir -p $(dir $@); \ cat $< | \ (set -e; \ echo "#ifndef __ASM_OFFSETS_H__"; \ @@ -43,6 +44,6 @@ arch/$(ARCH)/kernel/asm-offsets.s: arch/$(ARCH)/kernel/asm-offsets.c FORCE $(Q)mkdir -p $(dir $@) $(call if_changed_dep,cc_s_c) -$(srctree)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild +$(obj)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild $(call cmd,offsets) diff --git a/Makefile b/Makefile index 524fb48fa334f..382298f37adfb 100644 --- a/Makefile +++ b/Makefile @@ -814,7 +814,7 @@ ifneq ($(KBUILD_MODULES),) endif prepare0: prepare prepare1 FORCE - $(Q)$(MAKE) $(build)=$(srctree) + $(Q)$(MAKE) $(build)=. # All the preparing.. prepare-all: prepare0 -- GitLab From d3fd4c2d48ac4590a922f2a950a2d46386c97a8a Mon Sep 17 00:00:00 2001 From: Al Viro <viro@ZenIV.linux.org.uk> Date: Sun, 11 Sep 2005 00:24:27 +0100 Subject: [PATCH 440/563] [PATCH] uml spinlock breakage mingo missed that one... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-um/spinlock_types.h | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 include/asm-um/spinlock_types.h diff --git a/include/asm-um/spinlock_types.h b/include/asm-um/spinlock_types.h new file mode 100644 index 0000000000000..e5a94294bf824 --- /dev/null +++ b/include/asm-um/spinlock_types.h @@ -0,0 +1,6 @@ +#ifndef __UM_SPINLOCK_TYPES_H +#define __UM_SPINLOCK_TYPES_H + +#include "asm/arch/spinlock_types.h" + +#endif -- GitLab From e130af5dab2abbf01c5d92ec5ac05912cf3d9aa7 Mon Sep 17 00:00:00 2001 From: Herbert Xu <herbert@gondor.apana.org.au> Date: Sat, 10 Sep 2005 17:19:09 -0700 Subject: [PATCH 441/563] [TCP]: Fix double adjustment of tp->{lost,left}_out in tcp_fragment(). There is an extra left_out/lost_out adjustment in tcp_fragment which means that the lost_out accounting is always wrong. This patch removes that chunk of code. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net> --- net/ipv4/tcp_output.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 15e1134da1b2a..c10e4435e3b12 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -485,11 +485,6 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when; buff->tstamp = skb->tstamp; - if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { - tp->lost_out -= tcp_skb_pcount(skb); - tp->left_out -= tcp_skb_pcount(skb); - } - old_factor = tcp_skb_pcount(skb); /* Fix up tso_factor for both original and new SKB. */ -- GitLab From 2d21247998c5d183179a7e822c4032974a53ff49 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan <adobriyan@gmail.com> Date: Sun, 11 Sep 2005 04:01:09 +0400 Subject: [PATCH 442/563] [PATCH] Fix breakage on ppc{,64} by "nvidiafb: Fallback to firmware EDID" Fix drivers/video/nvidia/nv_of.c:34: error: conflicting types for 'nvidia_probe_i2c_connector' drivers/video/nvidia/nv_proto.h:38: error: previous declaration of 'nvidia_probe_i2c_connector' was here Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Acked-by: Al Viro <viro@ZenIV.linux.org.uk> Acked-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/nvidia/nv_of.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c index 7d12eb85310de..4fa2cf9a8af2a 100644 --- a/drivers/video/nvidia/nv_of.c +++ b/drivers/video/nvidia/nv_of.c @@ -30,8 +30,9 @@ void nvidia_create_i2c_busses(struct nvidia_par *par) {} void nvidia_delete_i2c_busses(struct nvidia_par *par) {} -int nvidia_probe_i2c_connector(struct nvidia_par *par, int conn, u8 **out_edid) +int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) { + struct nvidia_par *par = info->par; struct device_node *dp; unsigned char *pedid = NULL; unsigned char *disptype = NULL; -- GitLab From 05c45ca9aa4ec57e8e22341633c7a98cc879423d Mon Sep 17 00:00:00 2001 From: Russell King <rmk@dyn-67.arm.linux.org.uk> Date: Sun, 11 Sep 2005 10:26:31 +0100 Subject: [PATCH 443/563] [MFD] Add code UCB1200/UCB1300 device support Add the core device support code for the Philips UCB1200 and UCB1300 devices. Also includes the following from Pavel: This fixes u32 vs. pm_message_t confusion and uses cleaner try_to_freeze() [fixing compilation as a side-effect on newer kernels.] Signed-off-by: Pavel Machek <pavel@suse.cz> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- drivers/mfd/Kconfig | 5 + drivers/mfd/Makefile | 1 + drivers/mfd/ucb1x00-core.c | 665 +++++++++++++++++++++++++++++++++++++ drivers/mfd/ucb1x00.h | 256 ++++++++++++++ 4 files changed, 927 insertions(+) create mode 100644 drivers/mfd/ucb1x00-core.c create mode 100644 drivers/mfd/ucb1x00.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1588a59e3767a..1f8563bde4a91 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -13,4 +13,9 @@ config MCP_SA11X0 depends on ARCH_SA1100 select MCP +# Chip drivers +config MCP_UCB1200 + tristate "Support for UCB1200 / UCB1300" + depends on MCP + endmenu diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 98bdd6a421889..90815b2840219 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o +obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c new file mode 100644 index 0000000000000..10f6ce1bc0abc --- /dev/null +++ b/drivers/mfd/ucb1x00-core.c @@ -0,0 +1,665 @@ +/* + * linux/drivers/mfd/ucb1x00-core.c + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + * + * 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. + * + * The UCB1x00 core driver provides basic services for handling IO, + * the ADC, interrupts, and accessing registers. It is designed + * such that everything goes through this layer, thereby providing + * a consistent locking methodology, as well as allowing the drivers + * to be used on other non-MCP-enabled hardware platforms. + * + * Note that all locks are private to this file. Nothing else may + * touch them. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/device.h> + +#include <asm/dma.h> +#include <asm/hardware.h> +#include <asm/irq.h> + +#include "ucb1x00.h" + +static DECLARE_MUTEX(ucb1x00_sem); +static LIST_HEAD(ucb1x00_drivers); +static LIST_HEAD(ucb1x00_devices); + +/** + * ucb1x00_io_set_dir - set IO direction + * @ucb: UCB1x00 structure describing chip + * @in: bitfield of IO pins to be set as inputs + * @out: bitfield of IO pins to be set as outputs + * + * Set the IO direction of the ten general purpose IO pins on + * the UCB1x00 chip. The @in bitfield has priority over the + * @out bitfield, in that if you specify a pin as both input + * and output, it will end up as an input. + * + * ucb1x00_enable must have been called to enable the comms + * before using this function. + * + * This function takes a spinlock, disabling interrupts. + */ +void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int in, unsigned int out) +{ + unsigned long flags; + + spin_lock_irqsave(&ucb->io_lock, flags); + ucb->io_dir |= out; + ucb->io_dir &= ~in; + + ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); + spin_unlock_irqrestore(&ucb->io_lock, flags); +} + +/** + * ucb1x00_io_write - set or clear IO outputs + * @ucb: UCB1x00 structure describing chip + * @set: bitfield of IO pins to set to logic '1' + * @clear: bitfield of IO pins to set to logic '0' + * + * Set the IO output state of the specified IO pins. The value + * is retained if the pins are subsequently configured as inputs. + * The @clear bitfield has priority over the @set bitfield - + * outputs will be cleared. + * + * ucb1x00_enable must have been called to enable the comms + * before using this function. + * + * This function takes a spinlock, disabling interrupts. + */ +void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear) +{ + unsigned long flags; + + spin_lock_irqsave(&ucb->io_lock, flags); + ucb->io_out |= set; + ucb->io_out &= ~clear; + + ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); + spin_unlock_irqrestore(&ucb->io_lock, flags); +} + +/** + * ucb1x00_io_read - read the current state of the IO pins + * @ucb: UCB1x00 structure describing chip + * + * Return a bitfield describing the logic state of the ten + * general purpose IO pins. + * + * ucb1x00_enable must have been called to enable the comms + * before using this function. + * + * This function does not take any semaphores or spinlocks. + */ +unsigned int ucb1x00_io_read(struct ucb1x00 *ucb) +{ + return ucb1x00_reg_read(ucb, UCB_IO_DATA); +} + +/* + * UCB1300 data sheet says we must: + * 1. enable ADC => 5us (including reference startup time) + * 2. select input => 51*tsibclk => 4.3us + * 3. start conversion => 102*tsibclk => 8.5us + * (tsibclk = 1/11981000) + * Period between SIB 128-bit frames = 10.7us + */ + +/** + * ucb1x00_adc_enable - enable the ADC converter + * @ucb: UCB1x00 structure describing chip + * + * Enable the ucb1x00 and ADC converter on the UCB1x00 for use. + * Any code wishing to use the ADC converter must call this + * function prior to using it. + * + * This function takes the ADC semaphore to prevent two or more + * concurrent uses, and therefore may sleep. As a result, it + * can only be called from process context, not interrupt + * context. + * + * You should release the ADC as soon as possible using + * ucb1x00_adc_disable. + */ +void ucb1x00_adc_enable(struct ucb1x00 *ucb) +{ + down(&ucb->adc_sem); + + ucb->adc_cr |= UCB_ADC_ENA; + + ucb1x00_enable(ucb); + ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr); +} + +/** + * ucb1x00_adc_read - read the specified ADC channel + * @ucb: UCB1x00 structure describing chip + * @adc_channel: ADC channel mask + * @sync: wait for syncronisation pulse. + * + * Start an ADC conversion and wait for the result. Note that + * synchronised ADC conversions (via the ADCSYNC pin) must wait + * until the trigger is asserted and the conversion is finished. + * + * This function currently spins waiting for the conversion to + * complete (2 frames max without sync). + * + * If called for a synchronised ADC conversion, it may sleep + * with the ADC semaphore held. + */ +unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync) +{ + unsigned int val; + + if (sync) + adc_channel |= UCB_ADC_SYNC_ENA; + + ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel); + ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START); + + for (;;) { + val = ucb1x00_reg_read(ucb, UCB_ADC_DATA); + if (val & UCB_ADC_DAT_VAL) + break; + /* yield to other processes */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } + + return UCB_ADC_DAT(val); +} + +/** + * ucb1x00_adc_disable - disable the ADC converter + * @ucb: UCB1x00 structure describing chip + * + * Disable the ADC converter and release the ADC semaphore. + */ +void ucb1x00_adc_disable(struct ucb1x00 *ucb) +{ + ucb->adc_cr &= ~UCB_ADC_ENA; + ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr); + ucb1x00_disable(ucb); + + up(&ucb->adc_sem); +} + +/* + * UCB1x00 Interrupt handling. + * + * The UCB1x00 can generate interrupts when the SIBCLK is stopped. + * Since we need to read an internal register, we must re-enable + * SIBCLK to talk to the chip. We leave the clock running until + * we have finished processing all interrupts from the chip. + */ +static irqreturn_t ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs) +{ + struct ucb1x00 *ucb = devid; + struct ucb1x00_irq *irq; + unsigned int isr, i; + + ucb1x00_enable(ucb); + isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS); + ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr); + ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); + + for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++) + if (isr & 1 && irq->fn) + irq->fn(i, irq->devid); + ucb1x00_disable(ucb); + + return IRQ_HANDLED; +} + +/** + * ucb1x00_hook_irq - hook a UCB1x00 interrupt + * @ucb: UCB1x00 structure describing chip + * @idx: interrupt index + * @fn: function to call when interrupt is triggered + * @devid: device id to pass to interrupt handler + * + * Hook the specified interrupt. You can only register one handler + * for each interrupt source. The interrupt source is not enabled + * by this function; use ucb1x00_enable_irq instead. + * + * Interrupt handlers will be called with other interrupts enabled. + * + * Returns zero on success, or one of the following errors: + * -EINVAL if the interrupt index is invalid + * -EBUSY if the interrupt has already been hooked + */ +int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid) +{ + struct ucb1x00_irq *irq; + int ret = -EINVAL; + + if (idx < 16) { + irq = ucb->irq_handler + idx; + ret = -EBUSY; + + spin_lock_irq(&ucb->lock); + if (irq->fn == NULL) { + irq->devid = devid; + irq->fn = fn; + ret = 0; + } + spin_unlock_irq(&ucb->lock); + } + return ret; +} + +/** + * ucb1x00_enable_irq - enable an UCB1x00 interrupt source + * @ucb: UCB1x00 structure describing chip + * @idx: interrupt index + * @edges: interrupt edges to enable + * + * Enable the specified interrupt to trigger on %UCB_RISING, + * %UCB_FALLING or both edges. The interrupt should have been + * hooked by ucb1x00_hook_irq. + */ +void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges) +{ + unsigned long flags; + + if (idx < 16) { + spin_lock_irqsave(&ucb->lock, flags); + + ucb1x00_enable(ucb); + if (edges & UCB_RISING) { + ucb->irq_ris_enbl |= 1 << idx; + ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); + } + if (edges & UCB_FALLING) { + ucb->irq_fal_enbl |= 1 << idx; + ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl); + } + ucb1x00_disable(ucb); + spin_unlock_irqrestore(&ucb->lock, flags); + } +} + +/** + * ucb1x00_disable_irq - disable an UCB1x00 interrupt source + * @ucb: UCB1x00 structure describing chip + * @edges: interrupt edges to disable + * + * Disable the specified interrupt triggering on the specified + * (%UCB_RISING, %UCB_FALLING or both) edges. + */ +void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges) +{ + unsigned long flags; + + if (idx < 16) { + spin_lock_irqsave(&ucb->lock, flags); + + ucb1x00_enable(ucb); + if (edges & UCB_RISING) { + ucb->irq_ris_enbl &= ~(1 << idx); + ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); + } + if (edges & UCB_FALLING) { + ucb->irq_fal_enbl &= ~(1 << idx); + ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl); + } + ucb1x00_disable(ucb); + spin_unlock_irqrestore(&ucb->lock, flags); + } +} + +/** + * ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt + * @ucb: UCB1x00 structure describing chip + * @idx: interrupt index + * @devid: device id. + * + * Disable the interrupt source and remove the handler. devid must + * match the devid passed when hooking the interrupt. + * + * Returns zero on success, or one of the following errors: + * -EINVAL if the interrupt index is invalid + * -ENOENT if devid does not match + */ +int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid) +{ + struct ucb1x00_irq *irq; + int ret; + + if (idx >= 16) + goto bad; + + irq = ucb->irq_handler + idx; + ret = -ENOENT; + + spin_lock_irq(&ucb->lock); + if (irq->devid == devid) { + ucb->irq_ris_enbl &= ~(1 << idx); + ucb->irq_fal_enbl &= ~(1 << idx); + + ucb1x00_enable(ucb); + ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); + ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl); + ucb1x00_disable(ucb); + + irq->fn = NULL; + irq->devid = NULL; + ret = 0; + } + spin_unlock_irq(&ucb->lock); + return ret; + +bad: + printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx); + return -EINVAL; +} + +static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv) +{ + struct ucb1x00_dev *dev; + int ret = -ENOMEM; + + dev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL); + if (dev) { + dev->ucb = ucb; + dev->drv = drv; + + ret = drv->add(dev); + + if (ret == 0) { + list_add(&dev->dev_node, &ucb->devs); + list_add(&dev->drv_node, &drv->devs); + } else { + kfree(dev); + } + } + return ret; +} + +static void ucb1x00_remove_dev(struct ucb1x00_dev *dev) +{ + dev->drv->remove(dev); + list_del(&dev->dev_node); + list_del(&dev->drv_node); + kfree(dev); +} + +/* + * Try to probe our interrupt, rather than relying on lots of + * hard-coded machine dependencies. For reference, the expected + * IRQ mappings are: + * + * Machine Default IRQ + * adsbitsy IRQ_GPCIN4 + * cerf IRQ_GPIO_UCB1200_IRQ + * flexanet IRQ_GPIO_GUI + * freebird IRQ_GPIO_FREEBIRD_UCB1300_IRQ + * graphicsclient ADS_EXT_IRQ(8) + * graphicsmaster ADS_EXT_IRQ(8) + * lart LART_IRQ_UCB1200 + * omnimeter IRQ_GPIO23 + * pfs168 IRQ_GPIO_UCB1300_IRQ + * simpad IRQ_GPIO_UCB1300_IRQ + * shannon SHANNON_IRQ_GPIO_IRQ_CODEC + * yopy IRQ_GPIO_UCB1200_IRQ + */ +static int ucb1x00_detect_irq(struct ucb1x00 *ucb) +{ + unsigned long mask; + + mask = probe_irq_on(); + if (!mask) + return NO_IRQ; + + /* + * Enable the ADC interrupt. + */ + ucb1x00_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC); + ucb1x00_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC); + ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff); + ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); + + /* + * Cause an ADC interrupt. + */ + ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA); + ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START); + + /* + * Wait for the conversion to complete. + */ + while ((ucb1x00_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VAL) == 0); + ucb1x00_reg_write(ucb, UCB_ADC_CR, 0); + + /* + * Disable and clear interrupt. + */ + ucb1x00_reg_write(ucb, UCB_IE_RIS, 0); + ucb1x00_reg_write(ucb, UCB_IE_FAL, 0); + ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff); + ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); + + /* + * Read triggered interrupt. + */ + return probe_irq_off(mask); +} + +static int ucb1x00_probe(struct mcp *mcp) +{ + struct ucb1x00 *ucb; + struct ucb1x00_driver *drv; + unsigned int id; + int ret = -ENODEV; + + mcp_enable(mcp); + id = mcp_reg_read(mcp, UCB_ID); + + if (id != UCB_ID_1200 && id != UCB_ID_1300) { + printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); + goto err_disable; + } + + ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL); + ret = -ENOMEM; + if (!ucb) + goto err_disable; + + memset(ucb, 0, sizeof(struct ucb1x00)); + + ucb->cdev.class = &ucb1x00_class; + ucb->cdev.dev = &mcp->attached_device; + strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id)); + + spin_lock_init(&ucb->lock); + spin_lock_init(&ucb->io_lock); + sema_init(&ucb->adc_sem, 1); + + ucb->id = id; + ucb->mcp = mcp; + ucb->irq = ucb1x00_detect_irq(ucb); + if (ucb->irq == NO_IRQ) { + printk(KERN_ERR "UCB1x00: IRQ probe failed\n"); + ret = -ENODEV; + goto err_free; + } + + ret = request_irq(ucb->irq, ucb1x00_irq, 0, "UCB1x00", ucb); + if (ret) { + printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", + ucb->irq, ret); + goto err_free; + } + + set_irq_type(ucb->irq, IRQT_RISING); + mcp_set_drvdata(mcp, ucb); + + ret = class_device_register(&ucb->cdev); + if (ret) + goto err_irq; + + INIT_LIST_HEAD(&ucb->devs); + down(&ucb1x00_sem); + list_add(&ucb->node, &ucb1x00_devices); + list_for_each_entry(drv, &ucb1x00_drivers, node) { + ucb1x00_add_dev(ucb, drv); + } + up(&ucb1x00_sem); + goto out; + + err_irq: + free_irq(ucb->irq, ucb); + err_free: + kfree(ucb); + err_disable: + mcp_disable(mcp); + out: + return ret; +} + +static void ucb1x00_remove(struct mcp *mcp) +{ + struct ucb1x00 *ucb = mcp_get_drvdata(mcp); + struct list_head *l, *n; + + down(&ucb1x00_sem); + list_del(&ucb->node); + list_for_each_safe(l, n, &ucb->devs) { + struct ucb1x00_dev *dev = list_entry(l, struct ucb1x00_dev, dev_node); + ucb1x00_remove_dev(dev); + } + up(&ucb1x00_sem); + + free_irq(ucb->irq, ucb); + class_device_unregister(&ucb->cdev); +} + +static void ucb1x00_release(struct class_device *dev) +{ + struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); + kfree(ucb); +} + +static struct class ucb1x00_class = { + .name = "ucb1x00", + .release = ucb1x00_release, +}; + +int ucb1x00_register_driver(struct ucb1x00_driver *drv) +{ + struct ucb1x00 *ucb; + + INIT_LIST_HEAD(&drv->devs); + down(&ucb1x00_sem); + list_add(&drv->node, &ucb1x00_drivers); + list_for_each_entry(ucb, &ucb1x00_devices, node) { + ucb1x00_add_dev(ucb, drv); + } + up(&ucb1x00_sem); + return 0; +} + +void ucb1x00_unregister_driver(struct ucb1x00_driver *drv) +{ + struct list_head *n, *l; + + down(&ucb1x00_sem); + list_del(&drv->node); + list_for_each_safe(l, n, &drv->devs) { + struct ucb1x00_dev *dev = list_entry(l, struct ucb1x00_dev, drv_node); + ucb1x00_remove_dev(dev); + } + up(&ucb1x00_sem); +} + +static int ucb1x00_suspend(struct mcp *mcp, pm_message_t state) +{ + struct ucb1x00 *ucb = mcp_get_drvdata(mcp); + struct ucb1x00_dev *dev; + + down(&ucb1x00_sem); + list_for_each_entry(dev, &ucb->devs, dev_node) { + if (dev->drv->suspend) + dev->drv->suspend(dev, state); + } + up(&ucb1x00_sem); + return 0; +} + +static int ucb1x00_resume(struct mcp *mcp) +{ + struct ucb1x00 *ucb = mcp_get_drvdata(mcp); + struct ucb1x00_dev *dev; + + down(&ucb1x00_sem); + list_for_each_entry(dev, &ucb->devs, dev_node) { + if (dev->drv->resume) + dev->drv->resume(dev); + } + up(&ucb1x00_sem); + return 0; +} + +static struct mcp_driver ucb1x00_driver = { + .drv = { + .name = "ucb1x00", + }, + .probe = ucb1x00_probe, + .remove = ucb1x00_remove, + .suspend = ucb1x00_suspend, + .resume = ucb1x00_resume, +}; + +static int __init ucb1x00_init(void) +{ + int ret = class_register(&ucb1x00_class); + if (ret == 0) { + ret = mcp_driver_register(&ucb1x00_driver); + if (ret) + class_unregister(&ucb1x00_class); + } + return ret; +} + +static void __exit ucb1x00_exit(void) +{ + mcp_driver_unregister(&ucb1x00_driver); + class_unregister(&ucb1x00_class); +} + +module_init(ucb1x00_init); +module_exit(ucb1x00_exit); + +EXPORT_SYMBOL(ucb1x00_class); + +EXPORT_SYMBOL(ucb1x00_io_set_dir); +EXPORT_SYMBOL(ucb1x00_io_write); +EXPORT_SYMBOL(ucb1x00_io_read); + +EXPORT_SYMBOL(ucb1x00_adc_enable); +EXPORT_SYMBOL(ucb1x00_adc_read); +EXPORT_SYMBOL(ucb1x00_adc_disable); + +EXPORT_SYMBOL(ucb1x00_hook_irq); +EXPORT_SYMBOL(ucb1x00_free_irq); +EXPORT_SYMBOL(ucb1x00_enable_irq); +EXPORT_SYMBOL(ucb1x00_disable_irq); + +EXPORT_SYMBOL(ucb1x00_register_driver); +EXPORT_SYMBOL(ucb1x00_unregister_driver); + +MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); +MODULE_DESCRIPTION("UCB1x00 core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h new file mode 100644 index 0000000000000..6b632644f59a1 --- /dev/null +++ b/drivers/mfd/ucb1x00.h @@ -0,0 +1,256 @@ +/* + * linux/drivers/mfd/ucb1x00.h + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + * + * 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. + */ +#ifndef UCB1200_H +#define UCB1200_H + +#define UCB_IO_DATA 0x00 +#define UCB_IO_DIR 0x01 + +#define UCB_IO_0 (1 << 0) +#define UCB_IO_1 (1 << 1) +#define UCB_IO_2 (1 << 2) +#define UCB_IO_3 (1 << 3) +#define UCB_IO_4 (1 << 4) +#define UCB_IO_5 (1 << 5) +#define UCB_IO_6 (1 << 6) +#define UCB_IO_7 (1 << 7) +#define UCB_IO_8 (1 << 8) +#define UCB_IO_9 (1 << 9) + +#define UCB_IE_RIS 0x02 +#define UCB_IE_FAL 0x03 +#define UCB_IE_STATUS 0x04 +#define UCB_IE_CLEAR 0x04 +#define UCB_IE_ADC (1 << 11) +#define UCB_IE_TSPX (1 << 12) +#define UCB_IE_TSMX (1 << 13) +#define UCB_IE_TCLIP (1 << 14) +#define UCB_IE_ACLIP (1 << 15) + +#define UCB_IRQ_TSPX 12 + +#define UCB_TC_A 0x05 +#define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */ +#define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */ + +#define UCB_TC_B 0x06 +#define UCB_TC_B_VOICE_ENA (1 << 3) +#define UCB_TC_B_CLIP (1 << 4) +#define UCB_TC_B_ATT (1 << 6) +#define UCB_TC_B_SIDE_ENA (1 << 11) +#define UCB_TC_B_MUTE (1 << 13) +#define UCB_TC_B_IN_ENA (1 << 14) +#define UCB_TC_B_OUT_ENA (1 << 15) + +#define UCB_AC_A 0x07 +#define UCB_AC_B 0x08 +#define UCB_AC_B_LOOP (1 << 8) +#define UCB_AC_B_MUTE (1 << 13) +#define UCB_AC_B_IN_ENA (1 << 14) +#define UCB_AC_B_OUT_ENA (1 << 15) + +#define UCB_TS_CR 0x09 +#define UCB_TS_CR_TSMX_POW (1 << 0) +#define UCB_TS_CR_TSPX_POW (1 << 1) +#define UCB_TS_CR_TSMY_POW (1 << 2) +#define UCB_TS_CR_TSPY_POW (1 << 3) +#define UCB_TS_CR_TSMX_GND (1 << 4) +#define UCB_TS_CR_TSPX_GND (1 << 5) +#define UCB_TS_CR_TSMY_GND (1 << 6) +#define UCB_TS_CR_TSPY_GND (1 << 7) +#define UCB_TS_CR_MODE_INT (0 << 8) +#define UCB_TS_CR_MODE_PRES (1 << 8) +#define UCB_TS_CR_MODE_POS (2 << 8) +#define UCB_TS_CR_BIAS_ENA (1 << 11) +#define UCB_TS_CR_TSPX_LOW (1 << 12) +#define UCB_TS_CR_TSMX_LOW (1 << 13) + +#define UCB_ADC_CR 0x0a +#define UCB_ADC_SYNC_ENA (1 << 0) +#define UCB_ADC_VREFBYP_CON (1 << 1) +#define UCB_ADC_INP_TSPX (0 << 2) +#define UCB_ADC_INP_TSMX (1 << 2) +#define UCB_ADC_INP_TSPY (2 << 2) +#define UCB_ADC_INP_TSMY (3 << 2) +#define UCB_ADC_INP_AD0 (4 << 2) +#define UCB_ADC_INP_AD1 (5 << 2) +#define UCB_ADC_INP_AD2 (6 << 2) +#define UCB_ADC_INP_AD3 (7 << 2) +#define UCB_ADC_EXT_REF (1 << 5) +#define UCB_ADC_START (1 << 7) +#define UCB_ADC_ENA (1 << 15) + +#define UCB_ADC_DATA 0x0b +#define UCB_ADC_DAT_VAL (1 << 15) +#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5) + +#define UCB_ID 0x0c +#define UCB_ID_1200 0x1004 +#define UCB_ID_1300 0x1005 + +#define UCB_MODE 0x0d +#define UCB_MODE_DYN_VFLAG_ENA (1 << 12) +#define UCB_MODE_AUD_OFF_CAN (1 << 13) + +#include "mcp.h" + +struct ucb1x00_irq { + void *devid; + void (*fn)(int, void *); +}; + +extern struct class ucb1x00_class; + +struct ucb1x00 { + spinlock_t lock; + struct mcp *mcp; + unsigned int irq; + struct semaphore adc_sem; + spinlock_t io_lock; + u16 id; + u16 io_dir; + u16 io_out; + u16 adc_cr; + u16 irq_fal_enbl; + u16 irq_ris_enbl; + struct ucb1x00_irq irq_handler[16]; + struct class_device cdev; + struct list_head node; + struct list_head devs; +}; + +struct ucb1x00_driver; + +struct ucb1x00_dev { + struct list_head dev_node; + struct list_head drv_node; + struct ucb1x00 *ucb; + struct ucb1x00_driver *drv; + void *priv; +}; + +struct ucb1x00_driver { + struct list_head node; + struct list_head devs; + int (*add)(struct ucb1x00_dev *dev); + void (*remove)(struct ucb1x00_dev *dev); + int (*suspend)(struct ucb1x00_dev *dev, pm_message_t state); + int (*resume)(struct ucb1x00_dev *dev); +}; + +#define classdev_to_ucb1x00(cd) container_of(cd, struct ucb1x00, cdev) + +int ucb1x00_register_driver(struct ucb1x00_driver *); +void ucb1x00_unregister_driver(struct ucb1x00_driver *); + +/** + * ucb1x00_clkrate - return the UCB1x00 SIB clock rate + * @ucb: UCB1x00 structure describing chip + * + * Return the SIB clock rate in Hz. + */ +static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb) +{ + return mcp_get_sclk_rate(ucb->mcp); +} + +/** + * ucb1x00_enable - enable the UCB1x00 SIB clock + * @ucb: UCB1x00 structure describing chip + * + * Enable the SIB clock. This can be called multiple times. + */ +static inline void ucb1x00_enable(struct ucb1x00 *ucb) +{ + mcp_enable(ucb->mcp); +} + +/** + * ucb1x00_disable - disable the UCB1x00 SIB clock + * @ucb: UCB1x00 structure describing chip + * + * Disable the SIB clock. The SIB clock will only be disabled + * when the number of ucb1x00_enable calls match the number of + * ucb1x00_disable calls. + */ +static inline void ucb1x00_disable(struct ucb1x00 *ucb) +{ + mcp_disable(ucb->mcp); +} + +/** + * ucb1x00_reg_write - write a UCB1x00 register + * @ucb: UCB1x00 structure describing chip + * @reg: UCB1x00 4-bit register index to write + * @val: UCB1x00 16-bit value to write + * + * Write the UCB1x00 register @reg with value @val. The SIB + * clock must be running for this function to return. + */ +static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val) +{ + mcp_reg_write(ucb->mcp, reg, val); +} + +/** + * ucb1x00_reg_read - read a UCB1x00 register + * @ucb: UCB1x00 structure describing chip + * @reg: UCB1x00 4-bit register index to write + * + * Read the UCB1x00 register @reg and return its value. The SIB + * clock must be running for this function to return. + */ +static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg) +{ + return mcp_reg_read(ucb->mcp, reg); +} +/** + * ucb1x00_set_audio_divisor - + * @ucb: UCB1x00 structure describing chip + * @div: SIB clock divisor + */ +static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div) +{ + mcp_set_audio_divisor(ucb->mcp, div); +} + +/** + * ucb1x00_set_telecom_divisor - + * @ucb: UCB1x00 structure describing chip + * @div: SIB clock divisor + */ +static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div) +{ + mcp_set_telecom_divisor(ucb->mcp, div); +} + +void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int); +void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int); +unsigned int ucb1x00_io_read(struct ucb1x00 *ucb); + +#define UCB_NOSYNC (0) +#define UCB_SYNC (1) + +unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync); +void ucb1x00_adc_enable(struct ucb1x00 *ucb); +void ucb1x00_adc_disable(struct ucb1x00 *ucb); + +/* + * Which edges of the IRQ do you want to control today? + */ +#define UCB_RISING (1 << 0) +#define UCB_FALLING (1 << 1) + +int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid); +void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges); +void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges); +int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid); + +#endif -- GitLab From acb45439a89c6830349c02405f00a7208db0a66b Mon Sep 17 00:00:00 2001 From: Russell King <rmk@dyn-67.arm.linux.org.uk> Date: Sun, 11 Sep 2005 10:26:57 +0100 Subject: [PATCH 444/563] [MFD] Add code UCB1200/UCB1300 touchscreen support Add support for Philips UCB1200 and UCB1300 touchscreen interfaces found on ARM devices. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- drivers/mfd/Kconfig | 4 + drivers/mfd/Makefile | 1 + drivers/mfd/ucb1x00-ts.c | 430 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 drivers/mfd/ucb1x00-ts.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1f8563bde4a91..550f29744812f 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -18,4 +18,8 @@ config MCP_UCB1200 tristate "Support for UCB1200 / UCB1300" depends on MCP +config MCP_UCB1200_TS + tristate "Touchscreen interface support" + depends on MCP_UCB1200 && INPUT + endmenu diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 90815b2840219..a05cd1599a704 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o +obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c new file mode 100644 index 0000000000000..52e0699eeb8ba --- /dev/null +++ b/drivers/mfd/ucb1x00-ts.c @@ -0,0 +1,430 @@ +/* + * linux/drivers/mfd/ucb1x00-ts.c + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 21-Jan-2002 <jco@ict.es> : + * + * Added support for synchronous A/D mode. This mode is useful to + * avoid noise induced in the touchpanel by the LCD, provided that + * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin. + * It is important to note that the signal connected to the ADCSYNC + * pin should provide pulses even when the LCD is blanked, otherwise + * a pen touch needed to unblank the LCD will never be read. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/sched.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/input.h> +#include <linux/device.h> +#include <linux/suspend.h> +#include <linux/slab.h> + +#include <asm/dma.h> +#include <asm/semaphore.h> + +#include "ucb1x00.h" + + +struct ucb1x00_ts { + struct input_dev idev; + struct ucb1x00 *ucb; + + wait_queue_head_t irq_wait; + struct semaphore sem; + struct completion init_exit; + struct task_struct *rtask; + int use_count; + u16 x_res; + u16 y_res; + + int restart:1; + int adcsync:1; +}; + +static int adcsync; + +static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y) +{ + input_report_abs(&ts->idev, ABS_X, x); + input_report_abs(&ts->idev, ABS_Y, y); + input_report_abs(&ts->idev, ABS_PRESSURE, pressure); + input_sync(&ts->idev); +} + +static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) +{ + input_report_abs(&ts->idev, ABS_PRESSURE, 0); + input_sync(&ts->idev); +} + +/* + * Switch to interrupt mode. + */ +static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts) +{ + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | + UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | + UCB_TS_CR_MODE_INT); +} + +/* + * Switch to pressure mode, and read pressure. We don't need to wait + * here, since both plates are being driven. + */ +static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts) +{ + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | + UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + + return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); +} + +/* + * Switch to X position mode and measure Y plate. We switch the plate + * configuration in pressure mode, then switch to position mode. This + * gives a faster response time. Even so, we need to wait about 55us + * for things to stabilise. + */ +static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts) +{ + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | + UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); + + udelay(55); + + return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); +} + +/* + * Switch to Y position mode and measure X plate. We switch the plate + * configuration in pressure mode, then switch to position mode. This + * gives a faster response time. Even so, we need to wait about 55us + * for things to stabilise. + */ +static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts) +{ + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | + UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); + + udelay(55); + + return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); +} + +/* + * Switch to X plate resistance mode. Set MX to ground, PX to + * supply. Measure current. + */ +static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts) +{ + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); +} + +/* + * Switch to Y plate resistance mode. Set MY to ground, PY to + * supply. Measure current. + */ +static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts) +{ + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, + UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | + UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); + return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); +} + +/* + * This is a RT kernel thread that handles the ADC accesses + * (mainly so we can use semaphores in the UCB1200 core code + * to serialise accesses to the ADC). + */ +static int ucb1x00_thread(void *_ts) +{ + struct ucb1x00_ts *ts = _ts; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + int valid; + + ts->rtask = tsk; + + daemonize("ktsd"); + /* only want to receive SIGKILL */ + allow_signal(SIGKILL); + + /* + * We could run as a real-time thread. However, thus far + * this doesn't seem to be necessary. + */ +// tsk->policy = SCHED_FIFO; +// tsk->rt_priority = 1; + + complete(&ts->init_exit); + + valid = 0; + + add_wait_queue(&ts->irq_wait, &wait); + for (;;) { + unsigned int x, y, p, val; + signed long timeout; + + ts->restart = 0; + + ucb1x00_adc_enable(ts->ucb); + + x = ucb1x00_ts_read_xpos(ts); + y = ucb1x00_ts_read_ypos(ts); + p = ucb1x00_ts_read_pressure(ts); + + /* + * Switch back to interrupt mode. + */ + ucb1x00_ts_mode_int(ts); + ucb1x00_adc_disable(ts->ucb); + + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 100); + if (signal_pending(tsk)) + break; + + ucb1x00_enable(ts->ucb); + val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); + + if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) { + set_task_state(tsk, TASK_INTERRUPTIBLE); + + ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); + ucb1x00_disable(ts->ucb); + + /* + * If we spat out a valid sample set last time, + * spit out a "pen off" sample here. + */ + if (valid) { + ucb1x00_ts_event_release(ts); + valid = 0; + } + + timeout = MAX_SCHEDULE_TIMEOUT; + } else { + ucb1x00_disable(ts->ucb); + + /* + * Filtering is policy. Policy belongs in user + * space. We therefore leave it to user space + * to do any filtering they please. + */ + if (!ts->restart) { + ucb1x00_ts_evt_add(ts, p, x, y); + valid = 1; + } + + set_task_state(tsk, TASK_INTERRUPTIBLE); + timeout = HZ / 100; + } + + try_to_freeze(); + + schedule_timeout(timeout); + if (signal_pending(tsk)) + break; + } + + remove_wait_queue(&ts->irq_wait, &wait); + + ts->rtask = NULL; + complete_and_exit(&ts->init_exit, 0); +} + +/* + * We only detect touch screen _touches_ with this interrupt + * handler, and even then we just schedule our task. + */ +static void ucb1x00_ts_irq(int idx, void *id) +{ + struct ucb1x00_ts *ts = id; + ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); + wake_up(&ts->irq_wait); +} + +static int ucb1x00_ts_open(struct input_dev *idev) +{ + struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; + int ret = 0; + + if (down_interruptible(&ts->sem)) + return -EINTR; + + if (ts->use_count++ != 0) + goto out; + + if (ts->rtask) + panic("ucb1x00: rtask running?"); + + init_waitqueue_head(&ts->irq_wait); + ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); + if (ret < 0) + goto out; + + /* + * If we do this at all, we should allow the user to + * measure and read the X and Y resistance at any time. + */ + ucb1x00_adc_enable(ts->ucb); + ts->x_res = ucb1x00_ts_read_xres(ts); + ts->y_res = ucb1x00_ts_read_yres(ts); + ucb1x00_adc_disable(ts->ucb); + + init_completion(&ts->init_exit); + ret = kernel_thread(ucb1x00_thread, ts, CLONE_KERNEL); + if (ret >= 0) { + wait_for_completion(&ts->init_exit); + ret = 0; + } else { + ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); + } + + out: + if (ret) + ts->use_count--; + up(&ts->sem); + return ret; +} + +/* + * Release touchscreen resources. Disable IRQs. + */ +static void ucb1x00_ts_close(struct input_dev *idev) +{ + struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; + + down(&ts->sem); + if (--ts->use_count == 0) { + if (ts->rtask) { + send_sig(SIGKILL, ts->rtask, 1); + wait_for_completion(&ts->init_exit); + } + + ucb1x00_enable(ts->ucb); + ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); + ucb1x00_disable(ts->ucb); + } + up(&ts->sem); +} + +#ifdef CONFIG_PM +static int ucb1x00_ts_resume(struct ucb1x00_dev *dev) +{ + struct ucb1x00_ts *ts = dev->priv; + + if (ts->rtask != NULL) { + /* + * Restart the TS thread to ensure the + * TS interrupt mode is set up again + * after sleep. + */ + ts->restart = 1; + wake_up(&ts->irq_wait); + } + return 0; +} +#else +#define ucb1x00_ts_resume NULL +#endif + + +/* + * Initialisation. + */ +static int ucb1x00_ts_add(struct ucb1x00_dev *dev) +{ + struct ucb1x00_ts *ts; + + ts = kmalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + memset(ts, 0, sizeof(struct ucb1x00_ts)); + + ts->ucb = dev->ucb; + ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; + init_MUTEX(&ts->sem); + + ts->idev.name = "Touchscreen panel"; + ts->idev.id.product = ts->ucb->id; + ts->idev.open = ucb1x00_ts_open; + ts->idev.close = ucb1x00_ts_close; + + __set_bit(EV_ABS, ts->idev.evbit); + __set_bit(ABS_X, ts->idev.absbit); + __set_bit(ABS_Y, ts->idev.absbit); + __set_bit(ABS_PRESSURE, ts->idev.absbit); + + input_register_device(&ts->idev); + + dev->priv = ts; + + return 0; +} + +static void ucb1x00_ts_remove(struct ucb1x00_dev *dev) +{ + struct ucb1x00_ts *ts = dev->priv; + input_unregister_device(&ts->idev); + kfree(ts); +} + +static struct ucb1x00_driver ucb1x00_ts_driver = { + .add = ucb1x00_ts_add, + .remove = ucb1x00_ts_remove, + .resume = ucb1x00_ts_resume, +}; + +static int __init ucb1x00_ts_init(void) +{ + return ucb1x00_register_driver(&ucb1x00_ts_driver); +} + +static void __exit ucb1x00_ts_exit(void) +{ + ucb1x00_unregister_driver(&ucb1x00_ts_driver); +} + +module_param(adcsync, int, 0444); +module_init(ucb1x00_ts_init); +module_exit(ucb1x00_ts_exit); + +MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); +MODULE_DESCRIPTION("UCB1x00 touchscreen driver"); +MODULE_LICENSE("GPL"); -- GitLab From 48c92022ad264cb8084cee78a499f183b264e45f Mon Sep 17 00:00:00 2001 From: Russell King <rmk@dyn-67.arm.linux.org.uk> Date: Sun, 11 Sep 2005 10:27:23 +0100 Subject: [PATCH 445/563] [MFD] Add code UCB1200/UCB1300 assabet platform support Add support for Intel assabet specific board support for UCB1200/UCB1300 devices. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- drivers/mfd/Makefile | 4 ++ drivers/mfd/ucb1x00-assabet.c | 73 +++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 drivers/mfd/ucb1x00-assabet.c diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index a05cd1599a704..adb29b5368a8d 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -6,3 +6,7 @@ obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o + +ifeq ($(CONFIG_SA1100_ASSABET),y) +obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o +endif diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c new file mode 100644 index 0000000000000..e325fa71f38ba --- /dev/null +++ b/drivers/mfd/ucb1x00-assabet.c @@ -0,0 +1,73 @@ +/* + * linux/drivers/mfd/ucb1x00-assabet.c + * + * Copyright (C) 2001-2003 Russell King, All Rights Reserved. + * + * 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. + * + * We handle the machine-specific bits of the UCB1x00 driver here. + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/proc_fs.h> +#include <linux/device.h> + +#include <asm/dma.h> + +#include "ucb1x00.h" + +#define UCB1X00_ATTR(name,input)\ +static ssize_t name##_show(struct class_device *dev, char *buf) \ +{ \ + struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); \ + int val; \ + ucb1x00_adc_enable(ucb); \ + val = ucb1x00_adc_read(ucb, input, UCB_NOSYNC); \ + ucb1x00_adc_disable(ucb); \ + return sprintf(buf, "%d\n", val); \ +} \ +static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL) + +UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1); +UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0); +UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2); + +static int ucb1x00_assabet_add(struct ucb1x00_dev *dev) +{ + class_device_create_file(&dev->ucb->cdev, &class_device_attr_vbatt); + class_device_create_file(&dev->ucb->cdev, &class_device_attr_vcharger); + class_device_create_file(&dev->ucb->cdev, &class_device_attr_batt_temp); + return 0; +} + +static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev) +{ + class_device_remove_file(&dev->ucb->cdev, &class_device_attr_batt_temp); + class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vcharger); + class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vbatt); +} + +static struct ucb1x00_driver ucb1x00_assabet_driver = { + .add = ucb1x00_assabet_add, + .remove = ucb1x00_assabet_remove, +}; + +static int __init ucb1x00_assabet_init(void) +{ + return ucb1x00_register_driver(&ucb1x00_assabet_driver); +} + +static void __exit ucb1x00_assabet_exit(void) +{ + ucb1x00_unregister_driver(&ucb1x00_assabet_driver); +} + +module_init(ucb1x00_assabet_init); +module_exit(ucb1x00_assabet_exit); + +MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); +MODULE_DESCRIPTION("Assabet noddy testing only example ADC driver"); +MODULE_LICENSE("GPL"); -- GitLab From 5437775e0bc38d633c0a4b7660812f15b6693b69 Mon Sep 17 00:00:00 2001 From: Pavel Machek <pavel@suse.cz> Date: Sun, 11 Sep 2005 10:28:00 +0100 Subject: [PATCH 446/563] [MFD] Cleanups suggested by Dmitri, Vojtech and lists. These are small ucb1x00-ts cleanups, as suggested by Vojtech, Dmitri and the lists. Signed-off-by: Pavel Machek <pavel@suse.cz> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- drivers/mfd/ucb1x00-ts.c | 65 +++++++++++----------------------------- 1 file changed, 17 insertions(+), 48 deletions(-) diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 52e0699eeb8ba..a851d65c7cfef 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -1,7 +1,8 @@ /* - * linux/drivers/mfd/ucb1x00-ts.c + * Touchscreen driver for UCB1x00-based touchscreens * * Copyright (C) 2001 Russell King, All Rights Reserved. + * Copyright (C) 2005 Pavel Machek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -30,6 +31,7 @@ #include <linux/device.h> #include <linux/suspend.h> #include <linux/slab.h> +#include <linux/kthread.h> #include <asm/dma.h> #include <asm/semaphore.h> @@ -42,10 +44,7 @@ struct ucb1x00_ts { struct ucb1x00 *ucb; wait_queue_head_t irq_wait; - struct semaphore sem; - struct completion init_exit; struct task_struct *rtask; - int use_count; u16 x_res; u16 y_res; @@ -176,12 +175,6 @@ static int ucb1x00_thread(void *_ts) DECLARE_WAITQUEUE(wait, tsk); int valid; - ts->rtask = tsk; - - daemonize("ktsd"); - /* only want to receive SIGKILL */ - allow_signal(SIGKILL); - /* * We could run as a real-time thread. However, thus far * this doesn't seem to be necessary. @@ -189,12 +182,10 @@ static int ucb1x00_thread(void *_ts) // tsk->policy = SCHED_FIFO; // tsk->rt_priority = 1; - complete(&ts->init_exit); - valid = 0; add_wait_queue(&ts->irq_wait, &wait); - for (;;) { + while (!kthread_should_stop()) { unsigned int x, y, p, val; signed long timeout; @@ -212,10 +203,7 @@ static int ucb1x00_thread(void *_ts) ucb1x00_ts_mode_int(ts); ucb1x00_adc_disable(ts->ucb); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100); - if (signal_pending(tsk)) - break; + msleep(10); ucb1x00_enable(ts->ucb); val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); @@ -256,14 +244,12 @@ static int ucb1x00_thread(void *_ts) try_to_freeze(); schedule_timeout(timeout); - if (signal_pending(tsk)) - break; } remove_wait_queue(&ts->irq_wait, &wait); ts->rtask = NULL; - complete_and_exit(&ts->init_exit, 0); + return 0; } /* @@ -282,14 +268,7 @@ static int ucb1x00_ts_open(struct input_dev *idev) struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; int ret = 0; - if (down_interruptible(&ts->sem)) - return -EINTR; - - if (ts->use_count++ != 0) - goto out; - - if (ts->rtask) - panic("ucb1x00: rtask running?"); + BUG_ON(ts->rtask); init_waitqueue_head(&ts->irq_wait); ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); @@ -305,19 +284,16 @@ static int ucb1x00_ts_open(struct input_dev *idev) ts->y_res = ucb1x00_ts_read_yres(ts); ucb1x00_adc_disable(ts->ucb); - init_completion(&ts->init_exit); - ret = kernel_thread(ucb1x00_thread, ts, CLONE_KERNEL); - if (ret >= 0) { - wait_for_completion(&ts->init_exit); + ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd"); + if (!IS_ERR(ts->rtask)) { ret = 0; } else { ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); + ts->rtask = NULL; + ret = -EFAULT; } out: - if (ret) - ts->use_count--; - up(&ts->sem); return ret; } @@ -328,19 +304,13 @@ static void ucb1x00_ts_close(struct input_dev *idev) { struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; - down(&ts->sem); - if (--ts->use_count == 0) { - if (ts->rtask) { - send_sig(SIGKILL, ts->rtask, 1); - wait_for_completion(&ts->init_exit); - } + if (ts->rtask) + kthread_stop(ts->rtask); - ucb1x00_enable(ts->ucb); - ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); - ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); - ucb1x00_disable(ts->ucb); - } - up(&ts->sem); + ucb1x00_enable(ts->ucb); + ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); + ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); + ucb1x00_disable(ts->ucb); } #ifdef CONFIG_PM @@ -379,7 +349,6 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) ts->ucb = dev->ucb; ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; - init_MUTEX(&ts->sem); ts->idev.name = "Touchscreen panel"; ts->idev.id.product = ts->ucb->id; -- GitLab From 9ec4ff421f032f24416217f23b0c82dc9a5f38f6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@g5.osdl.org> Date: Sun, 11 Sep 2005 09:22:50 -0700 Subject: [PATCH 447/563] hpt366: write the full 4 bytes of ROM address, not just low 1 byte This is one heck of a confused driver. It uses a byte write to a dword register to enable a ROM resource that it doesn't even seem to be using. "Lost and wandering in the desert of confusion" Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/ide/pci/hpt366.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 7b64db10d1b03..127619a109eda 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1334,9 +1334,13 @@ static int __devinit init_hpt366(struct pci_dev *dev) static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name) { int ret = 0; - /* FIXME: Not portable */ + + /* + * FIXME: Not portable. Also, why do we enable the ROM in the first place? + * We don't seem to be using it. + */ if (dev->resource[PCI_ROM_RESOURCE].start) - pci_write_config_byte(dev, PCI_ROM_ADDRESS, + pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); -- GitLab From 4120b028dd231743935d954732045a87edda2a0a Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@g5.osdl.org> Date: Sun, 11 Sep 2005 09:26:20 -0700 Subject: [PATCH 448/563] Sun GEM ethernet: enable and map PCI ROM properly This same patch was reported to fix the MAC address detection on sunhme (next patch). Most people seem to be running this on Sparcs or PPC machines, where we get the MAC address from their respective firmware rather than from the (previously broken) ROM mapping routines. Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/net/sungem.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 3f67a42e8503f..de399563a9db2 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2817,7 +2817,7 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) #if (!defined(__sparc__) && !defined(CONFIG_PPC_PMAC)) /* Fetch MAC address from vital product data of PCI ROM. */ -static void find_eth_addr_in_vpd(void __iomem *rom_base, int len, unsigned char *dev_addr) +static int find_eth_addr_in_vpd(void __iomem *rom_base, int len, unsigned char *dev_addr) { int this_offset; @@ -2838,35 +2838,27 @@ static void find_eth_addr_in_vpd(void __iomem *rom_base, int len, unsigned char for (i = 0; i < 6; i++) dev_addr[i] = readb(p + i); - break; + return 1; } + return 0; } static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr) { - u32 rom_reg_orig; - void __iomem *p; - - if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) { - if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0) - goto use_random; - } + size_t size; + void __iomem *p = pci_map_rom(pdev, &size); - pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig); - pci_write_config_dword(pdev, pdev->rom_base_reg, - rom_reg_orig | PCI_ROM_ADDRESS_ENABLE); + if (p) { + int found; - p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024)); - if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa) - find_eth_addr_in_vpd(p, (64 * 1024), dev_addr); - - if (p != NULL) - iounmap(p); - - pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig); - return; + found = readb(p) == 0x55 && + readb(p + 1) == 0xaa && + find_eth_addr_in_vpd(p, (64 * 1024), dev_addr); + pci_unmap_rom(pdev, p); + if (found) + return; + } -use_random: /* Sun MAC prefix then 3 random bytes. */ dev_addr[0] = 0x08; dev_addr[1] = 0x00; -- GitLab From ce1289adeb67b5480f35cb257cbf6e9881153783 Mon Sep 17 00:00:00 2001 From: Willy Tarreau <willy@w.ods.org> Date: Sun, 11 Sep 2005 09:04:07 +0200 Subject: [PATCH 449/563] [PATCH] Sun HME: enable and map PCI ROM properly This ports the Sun GEM ROM mapping/enable fixes it sunhme (which used the same PCI ROM mapping code). Without this, I get NULL MAC addresses for all 4 ports (it's a SUN QFE). With it, I get the correct addresses (the ones printed on the label on the card). Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/net/sunhme.c | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index f02fe4119b2c8..9f046cae2f716 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2954,7 +2954,7 @@ static int is_quattro_p(struct pci_dev *pdev) } /* Fetch MAC address from vital product data of PCI ROM. */ -static void find_eth_addr_in_vpd(void __iomem *rom_base, int len, int index, unsigned char *dev_addr) +static int find_eth_addr_in_vpd(void __iomem *rom_base, int len, int index, unsigned char *dev_addr) { int this_offset; @@ -2977,42 +2977,33 @@ static void find_eth_addr_in_vpd(void __iomem *rom_base, int len, int index, uns for (i = 0; i < 6; i++) dev_addr[i] = readb(p + i); - break; + return 1; } index--; } + return 0; } static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr) { - u32 rom_reg_orig; - void __iomem *p; - int index; + size_t size; + void __iomem *p = pci_map_rom(pdev, &size); - index = 0; - if (is_quattro_p(pdev)) - index = PCI_SLOT(pdev->devfn); - - if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) { - if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0) - goto use_random; - } + if (p) { + int index = 0; + int found; - pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig); - pci_write_config_dword(pdev, pdev->rom_base_reg, - rom_reg_orig | PCI_ROM_ADDRESS_ENABLE); + if (is_quattro_p(pdev)) + index = PCI_SLOT(pdev->devfn); - p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024)); - if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa) - find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr); - - if (p != NULL) - iounmap(p); - - pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig); - return; + found = readb(p) == 0x55 && + readb(p + 1) == 0xaa && + find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr); + pci_unmap_rom(pdev, p); + if (found) + return; + } -use_random: /* Sun MAC prefix then 3 random bytes. */ dev_addr[0] = 0x08; dev_addr[1] = 0x00; -- GitLab From 5bb78269000cf326bfdfa19f79449c02a9158020 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.ravnborg.org> Date: Sun, 11 Sep 2005 22:30:22 +0200 Subject: [PATCH 450/563] kbuild: rename prepare to archprepare to fix dependency chain When introducing the generic asm-offsets.h support the dependency chain for the prepare targets was changed. All build scripts expecting include/asm/asm-offsets.h to be made when using the prepare target would broke. With the limited number of prepare targets left in arch Makefiles the trivial solution was to introduce a new arch specific target: archprepare The dependency chain looks like this now: prepare | +--> prepare0 | +--> archprepare | +--> scripts_basic +--> prepare1 | +---> prepare2 | +--> prepare3 So prepare 3 is processed before prepare2 etc. This guaantees that the asm symlink, version.h, scripts_basic are all updated before archprepare is processed. prepare0 which build the asm-offsets.h file will need the actions performed by archprepare. The head target is now named prepare, because users scripts will most likely use that target, but prepare-all has been kept for compatibility. Updated Documentation/kbuild/makefiles.txt. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- Documentation/kbuild/makefiles.txt | 14 +++++++------- Makefile | 23 +++++++++++++++-------- arch/arm/Makefile | 2 +- arch/cris/Makefile | 2 +- arch/ia64/Makefile | 2 +- arch/ppc/Makefile | 2 +- arch/sh/Makefile | 2 +- arch/sh64/Makefile | 2 +- arch/um/Makefile | 2 +- arch/xtensa/Makefile | 2 +- 10 files changed, 30 insertions(+), 23 deletions(-) diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 9a1586590d827..d802ce88bedc9 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -31,7 +31,7 @@ This document describes the Linux kernel Makefiles. === 6 Architecture Makefiles --- 6.1 Set variables to tweak the build to the architecture - --- 6.2 Add prerequisites to prepare: + --- 6.2 Add prerequisites to archprepare: --- 6.3 List directories to visit when descending --- 6.4 Architecture specific boot images --- 6.5 Building non-kbuild targets @@ -734,18 +734,18 @@ When kbuild executes the following steps are followed (roughly): for loadable kernel modules. ---- 6.2 Add prerequisites to prepare: +--- 6.2 Add prerequisites to archprepare: - The prepare: rule is used to list prerequisites that needs to be + The archprepare: rule is used to list prerequisites that needs to be built before starting to descend down in the subdirectories. This is usual header files containing assembler constants. Example: - #arch/s390/Makefile - prepare: include/asm-$(ARCH)/offsets.h + #arch/arm/Makefile + archprepare: maketools - In this example the file include/asm-$(ARCH)/offsets.h will - be built before descending down in the subdirectories. + In this example the file target maketools will be processed + before descending down in the subdirectories. See also chapter XXX-TODO that describe how kbuild supports generating offset header files. diff --git a/Makefile b/Makefile index 382298f37adfb..e90ee6a3eef4b 100644 --- a/Makefile +++ b/Makefile @@ -776,15 +776,20 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; # Error messages still appears in the original language .PHONY: $(vmlinux-dirs) -$(vmlinux-dirs): prepare-all scripts +$(vmlinux-dirs): prepare scripts $(Q)$(MAKE) $(build)=$@ # Things we need to do before we recursively start building the kernel -# or the modules are listed in "prepare-all". -# A multi level approach is used. prepare1 is updated first, then prepare0. -# prepare-all is the collection point for the prepare targets. +# or the modules are listed in "prepare". +# A multi level approach is used. prepareN is processed before prepareN-1. +# archprepare is used in arch Makefiles and when processed asm symlink, +# version.h and scripts_basic is processed / created. -.PHONY: prepare-all prepare prepare0 prepare1 prepare2 prepare3 +# Listed in dependency order +.PHONY: prepare archprepare prepare0 prepare1 prepare2 prepare3 + +# prepare-all is deprecated, use prepare as valid replacement +.PHONY: prepare-all # prepare3 is used to check if we are building in a separate output directory, # and if so do: @@ -813,11 +818,13 @@ ifneq ($(KBUILD_MODULES),) $(Q)mkdir -p $(MODVERDIR) endif -prepare0: prepare prepare1 FORCE +archprepare: prepare1 scripts_basic + +prepare0: archprepare FORCE $(Q)$(MAKE) $(build)=. # All the preparing.. -prepare-all: prepare0 +prepare prepare-all: prepare0 # Leave this as default for preprocessing vmlinux.lds.S, which is now # done in arch/$(ARCH)/kernel/Makefile @@ -908,7 +915,7 @@ modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) # Target to prepare building external modules .PHONY: modules_prepare -modules_prepare: prepare-all scripts +modules_prepare: prepare scripts # Target to install modules .PHONY: modules_install diff --git a/arch/arm/Makefile b/arch/arm/Makefile index e625ac66f49b2..130e6228b5871 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -175,7 +175,7 @@ else endif @touch $@ -prepare: maketools include/asm-arm/.arch +archprepare: maketools include/asm-arm/.arch .PHONY: maketools FORCE maketools: include/linux/version.h FORCE diff --git a/arch/cris/Makefile b/arch/cris/Makefile index a00043a91f16c..ea65d585cf5ec 100644 --- a/arch/cris/Makefile +++ b/arch/cris/Makefile @@ -107,7 +107,7 @@ archclean: rm -f timage vmlinux.bin decompress.bin rescue.bin cramfs.img rm -rf $(LD_SCRIPT).tmp -prepare: $(SRC_ARCH)/.links $(srctree)/include/asm-$(ARCH)/.arch +archprepare: $(SRC_ARCH)/.links $(srctree)/include/asm-$(ARCH)/.arch # Create some links to make all tools happy $(SRC_ARCH)/.links: diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 7ed678cf5e416..70f8ed2748d1b 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -82,7 +82,7 @@ unwcheck: vmlinux archclean: $(Q)$(MAKE) $(clean)=$(boot) -prepare: include/asm-ia64/.offsets.h.stamp +archprepare: include/asm-ia64/.offsets.h.stamp include/asm-ia64/.offsets.h.stamp: mkdir -p include/asm-ia64 diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 6dd7b50e06691..16e2675f3270b 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -107,7 +107,7 @@ archclean: # Temporary hack until we have migrated to asm-powerpc $(Q)rm -rf arch/$(ARCH)/include -prepare: checkbin +archprepare: checkbin # Temporary hack until we have migrated to asm-powerpc include/asm: arch/$(ARCH)/include/asm diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 19f00d57acf07..4a3049080b419 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -152,7 +152,7 @@ endif @touch $@ -prepare: maketools include/asm-sh/.cpu include/asm-sh/.mach +archprepare: maketools include/asm-sh/.cpu include/asm-sh/.mach .PHONY: maketools FORCE maketools: include/linux/version.h FORCE diff --git a/arch/sh64/Makefile b/arch/sh64/Makefile index 39073734a4761..8ca57ffa2b709 100644 --- a/arch/sh64/Makefile +++ b/arch/sh64/Makefile @@ -73,7 +73,7 @@ compressed: zImage archclean: $(Q)$(MAKE) $(clean)=$(boot) -prepare: arch/$(ARCH)/lib/syscalltab.h +archprepare: arch/$(ARCH)/lib/syscalltab.h define filechk_gen-syscalltab (set -e; \ diff --git a/arch/um/Makefile b/arch/um/Makefile index 154803a226984..ce987266dac62 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -107,7 +107,7 @@ else $(shell cd $(ARCH_DIR) && ln -sf Kconfig.$(SUBARCH) Kconfig.arch) endif -prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) +archprepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile index 67ef4cd173b9b..98fac8489aede 100644 --- a/arch/xtensa/Makefile +++ b/arch/xtensa/Makefile @@ -66,7 +66,7 @@ boot := arch/xtensa/boot archinc := include/asm-xtensa -prepare: $(archinc)/.platform +archprepare: $(archinc)/.platform # Update machine cpu and platform symlinks if something which affects # them changed. -- GitLab From 5011cdd01bedd66b314e330a638c97984c71b53d Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.ravnborg.org> Date: Sun, 11 Sep 2005 22:32:57 +0200 Subject: [PATCH 451/563] kbuild: fix silentoldconfig with make O= Al Viro reported that sometimes silentoldconfig failed because output directory was missing. So create it unconditionally before executing conf Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index e90ee6a3eef4b..45e5a38fbc7ae 100644 --- a/Makefile +++ b/Makefile @@ -491,6 +491,7 @@ include .config # If .config is newer than include/linux/autoconf.h, someone tinkered # with it and forgot to run make oldconfig include/linux/autoconf.h: .config + $(Q)mkdir -p include/linux $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig else # Dummy target needed, because used as prerequisite -- GitLab From e6c69bd39199656a8bbd0569edaff60574ff9cac Mon Sep 17 00:00:00 2001 From: Sam Ravnborg <sam@mars.ravnborg.org> Date: Sun, 11 Sep 2005 22:35:18 +0200 Subject: [PATCH 452/563] mips: rename offsets.c to asm-offsets.c Cannot build MIPS now. We need to change offset.c to asm-offsets.c Signed-off-by: Yoichi Yuasa <yuasa@hh.iij4u.or.jp> Signed-off-by: Sam Ravnborg <sam@ravnborg.org> --- arch/mips/kernel/{offset.c => asm-offsets.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename arch/mips/kernel/{offset.c => asm-offsets.c} (100%) diff --git a/arch/mips/kernel/offset.c b/arch/mips/kernel/asm-offsets.c similarity index 100% rename from arch/mips/kernel/offset.c rename to arch/mips/kernel/asm-offsets.c -- GitLab From a2a979821b6ab75a4f143cfaa1c4672cc259ec10 Mon Sep 17 00:00:00 2001 From: Keith Owens <kaos@sgi.com> Date: Sun, 11 Sep 2005 17:19:06 +1000 Subject: [PATCH 453/563] [PATCH] MCA/INIT: scheduler hooks Scheduler hooks to see/change which process is deemed to be on a cpu. Signed-off-by: Keith Owens <kaos@sgi.com> Signed-off-by: Tony Luck <tony.luck@intel.com> --- include/linux/sched.h | 2 ++ kernel/sched.c | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/linux/sched.h b/include/linux/sched.h index 4b83cb230006a..ed3bb19d13372 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -904,6 +904,8 @@ extern int task_curr(const task_t *p); extern int idle_cpu(int cpu); extern int sched_setscheduler(struct task_struct *, int, struct sched_param *); extern task_t *idle_task(int cpu); +extern task_t *curr_task(int cpu); +extern void set_curr_task(int cpu, task_t *p); void yield(void); diff --git a/kernel/sched.c b/kernel/sched.c index dbd4490afec14..e9ff04a9b56df 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3576,6 +3576,32 @@ task_t *idle_task(int cpu) return cpu_rq(cpu)->idle; } +/** + * curr_task - return the current task for a given cpu. + * @cpu: the processor in question. + */ +task_t *curr_task(int cpu) +{ + return cpu_curr(cpu); +} + +/** + * set_curr_task - set the current task for a given cpu. + * @cpu: the processor in question. + * @p: the task pointer to set. + * + * Description: This function must only be used when non-maskable interrupts + * are serviced on a separate stack. It allows the architecture to switch the + * notion of the current task on a cpu in a non-blocking manner. This function + * must be called with interrupts disabled, the caller must save the original + * value of the current task (see curr_task() above) and restore that value + * before reenabling interrupts. + */ +void set_curr_task(int cpu, task_t *p) +{ + cpu_curr(cpu) = p; +} + /** * find_process_by_pid - find a process with a matching PID value. * @pid: the pid in question. -- GitLab From e619ae0b96b6ace6629a6a0c6a5db23861ddaa78 Mon Sep 17 00:00:00 2001 From: Keith Owens <kaos@sgi.com> Date: Sun, 11 Sep 2005 17:20:14 +1000 Subject: [PATCH 454/563] [IA64] MCA/INIT: add an extra thread_info flag Add an extra thread_info flag to indicate the special MCA/INIT stacks. Mainly for debuggers. Signed-off-by: Keith Owens <kaos@sgi.com> Signed-off-by: Tony Luck <tony.luck@intel.com> --- include/asm-ia64/ptrace.h | 2 +- include/asm-ia64/thread_info.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h index c8766def9ee6f..fc544929ac34f 100644 --- a/include/asm-ia64/ptrace.h +++ b/include/asm-ia64/ptrace.h @@ -119,7 +119,7 @@ struct pt_regs { unsigned long ar_unat; /* interrupted task's NaT register (preserved) */ unsigned long ar_pfs; /* prev function state */ unsigned long ar_rsc; /* RSE configuration */ - /* The following two are valid only if cr_ipsr.cpl > 0: */ + /* The following two are valid only if cr_ipsr.cpl > 0 || ti->flags & _TIF_MCA_INIT */ unsigned long ar_rnat; /* RSE NaT */ unsigned long ar_bspstore; /* RSE bspstore */ diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h index b2c79f0694f8b..cf4a950a0f4f0 100644 --- a/include/asm-ia64/thread_info.h +++ b/include/asm-ia64/thread_info.h @@ -76,6 +76,7 @@ struct thread_info { #define TIF_SIGDELAYED 5 /* signal delayed from MCA/INIT/NMI/PMI context */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_MEMDIE 17 +#define TIF_MCA_INIT 18 /* this task is processing MCA or INIT */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) @@ -85,6 +86,7 @@ struct thread_info { #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_SIGDELAYED (1 << TIF_SIGDELAYED) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) +#define _TIF_MCA_INIT (1 << TIF_MCA_INIT) /* "work to do on user-return" bits */ #define TIF_ALLWORK_MASK (_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SIGDELAYED) -- GitLab From 289d773ee89ea80dcc364ef97d1be7ad1817387e Mon Sep 17 00:00:00 2001 From: Keith Owens <kaos@sgi.com> Date: Sun, 11 Sep 2005 17:21:46 +1000 Subject: [PATCH 455/563] [IA64] MCA/INIT: avoid reading INIT record during INIT event Reading the INIT record from SAL during the INIT event has proved to be unreliable, and a source of hangs during INIT processing. The new MCA/INIT handlers remove the need to get the INIT record from SAL. Change salinfo.c so mca.c can just flag that a new record is available, without having to read the record during INIT processing. This patch can be applied without the new MCA/INIT handlers. Also clean up some usage of NR_CPUS which should have been using cpu_online(). Signed-off-by: Keith Owens <kaos@sgi.com> Signed-off-by: Tony Luck <tony.luck@intel.com> --- arch/ia64/kernel/salinfo.c | 62 +++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c index 6f0cc7a6634ee..ca68e6e44a727 100644 --- a/arch/ia64/kernel/salinfo.c +++ b/arch/ia64/kernel/salinfo.c @@ -22,6 +22,11 @@ * * Dec 5 2004 kaos@sgi.com * Standardize which records are cleared automatically. + * + * Aug 18 2005 kaos@sgi.com + * mca.c may not pass a buffer, a NULL buffer just indicates that a new + * record is available in SAL. + * Replace some NR_CPUS by cpus_online, for hotplug cpu. */ #include <linux/types.h> @@ -193,7 +198,7 @@ shift1_data_saved (struct salinfo_data *data, int shift) * The buffer passed from mca.c points to the output from ia64_log_get. This is * a persistent buffer but its contents can change between the interrupt and * when user space processes the record. Save the record id to identify - * changes. + * changes. If the buffer is NULL then just update the bitmap. */ void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe) @@ -206,27 +211,29 @@ salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe) BUG_ON(type >= ARRAY_SIZE(salinfo_log_name)); - if (irqsafe) - spin_lock_irqsave(&data_saved_lock, flags); - for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) { - if (!data_saved->buffer) - break; - } - if (i == saved_size) { - if (!data->saved_num) { - shift1_data_saved(data, 0); - data_saved = data->data_saved + saved_size - 1; - } else - data_saved = NULL; - } - if (data_saved) { - data_saved->cpu = smp_processor_id(); - data_saved->id = ((sal_log_record_header_t *)buffer)->id; - data_saved->size = size; - data_saved->buffer = buffer; + if (buffer) { + if (irqsafe) + spin_lock_irqsave(&data_saved_lock, flags); + for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) { + if (!data_saved->buffer) + break; + } + if (i == saved_size) { + if (!data->saved_num) { + shift1_data_saved(data, 0); + data_saved = data->data_saved + saved_size - 1; + } else + data_saved = NULL; + } + if (data_saved) { + data_saved->cpu = smp_processor_id(); + data_saved->id = ((sal_log_record_header_t *)buffer)->id; + data_saved->size = size; + data_saved->buffer = buffer; + } + if (irqsafe) + spin_unlock_irqrestore(&data_saved_lock, flags); } - if (irqsafe) - spin_unlock_irqrestore(&data_saved_lock, flags); if (!test_and_set_bit(smp_processor_id(), &data->cpu_event)) { if (irqsafe) @@ -244,7 +251,7 @@ salinfo_timeout_check(struct salinfo_data *data) int i; if (!data->open) return; - for (i = 0; i < NR_CPUS; ++i) { + for_each_online_cpu(i) { if (test_bit(i, &data->cpu_event)) { /* double up() is not a problem, user space will see no * records for the additional "events". @@ -291,7 +298,7 @@ salinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t n = data->cpu_check; for (i = 0; i < NR_CPUS; i++) { - if (test_bit(n, &data->cpu_event)) { + if (test_bit(n, &data->cpu_event) && cpu_online(n)) { cpu = n; break; } @@ -585,11 +592,10 @@ salinfo_init(void) /* we missed any events before now */ online = 0; - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) { - set_bit(j, &data->cpu_event); - ++online; - } + for_each_online_cpu(j) { + set_bit(j, &data->cpu_event); + ++online; + } sema_init(&data->sem, online); *sdir++ = dir; -- GitLab From 7f613c7d2203ae137d98fc1c38abc30fd7048637 Mon Sep 17 00:00:00 2001 From: Keith Owens <kaos@sgi.com> Date: Sun, 11 Sep 2005 17:22:53 +1000 Subject: [PATCH 456/563] [PATCH] MCA/INIT: use per cpu stacks The bulk of the change. Use per cpu MCA/INIT stacks. Change the SAL to OS state (sos) to be per process. Do all the assembler work on the MCA/INIT stacks, leaving the original stack alone. Pass per cpu state data to the C handlers for MCA and INIT, which also means changing the mca_drv interfaces slightly. Lots of verification on whether the original stack is usable before converting it to a sleeping process. Signed-off-by: Keith Owens <kaos@sgi.com> Signed-off-by: Tony Luck <tony.luck@intel.com> --- arch/ia64/kernel/asm-offsets.c | 40 +- arch/ia64/kernel/mca.c | 821 +++++++++++-------- arch/ia64/kernel/mca_asm.S | 1358 +++++++++++++++++--------------- arch/ia64/kernel/mca_drv.c | 37 +- include/asm-ia64/mca.h | 102 ++- include/asm-ia64/mca_asm.h | 125 +-- 6 files changed, 1363 insertions(+), 1120 deletions(-) diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c index 7d1ae2982c533..f6a2342893418 100644 --- a/arch/ia64/kernel/asm-offsets.c +++ b/arch/ia64/kernel/asm-offsets.c @@ -211,17 +211,41 @@ void foo(void) #endif BLANK(); - DEFINE(IA64_MCA_CPU_PROC_STATE_DUMP_OFFSET, - offsetof (struct ia64_mca_cpu, proc_state_dump)); - DEFINE(IA64_MCA_CPU_STACK_OFFSET, - offsetof (struct ia64_mca_cpu, stack)); - DEFINE(IA64_MCA_CPU_STACKFRAME_OFFSET, - offsetof (struct ia64_mca_cpu, stackframe)); - DEFINE(IA64_MCA_CPU_RBSTORE_OFFSET, - offsetof (struct ia64_mca_cpu, rbstore)); + DEFINE(IA64_MCA_CPU_MCA_STACK_OFFSET, + offsetof (struct ia64_mca_cpu, mca_stack)); DEFINE(IA64_MCA_CPU_INIT_STACK_OFFSET, offsetof (struct ia64_mca_cpu, init_stack)); BLANK(); + DEFINE(IA64_SAL_OS_STATE_COMMON_OFFSET, + offsetof (struct ia64_sal_os_state, sal_ra)); + DEFINE(IA64_SAL_OS_STATE_OS_GP_OFFSET, + offsetof (struct ia64_sal_os_state, os_gp)); + DEFINE(IA64_SAL_OS_STATE_PAL_MIN_STATE_OFFSET, + offsetof (struct ia64_sal_os_state, pal_min_state)); + DEFINE(IA64_SAL_OS_STATE_PROC_STATE_PARAM_OFFSET, + offsetof (struct ia64_sal_os_state, proc_state_param)); + DEFINE(IA64_SAL_OS_STATE_SIZE, + sizeof (struct ia64_sal_os_state)); + DEFINE(IA64_PMSA_GR_OFFSET, + offsetof (struct pal_min_state_area_s, pmsa_gr)); + DEFINE(IA64_PMSA_BANK1_GR_OFFSET, + offsetof (struct pal_min_state_area_s, pmsa_bank1_gr)); + DEFINE(IA64_PMSA_PR_OFFSET, + offsetof (struct pal_min_state_area_s, pmsa_pr)); + DEFINE(IA64_PMSA_BR0_OFFSET, + offsetof (struct pal_min_state_area_s, pmsa_br0)); + DEFINE(IA64_PMSA_RSC_OFFSET, + offsetof (struct pal_min_state_area_s, pmsa_rsc)); + DEFINE(IA64_PMSA_IIP_OFFSET, + offsetof (struct pal_min_state_area_s, pmsa_iip)); + DEFINE(IA64_PMSA_IPSR_OFFSET, + offsetof (struct pal_min_state_area_s, pmsa_ipsr)); + DEFINE(IA64_PMSA_IFS_OFFSET, + offsetof (struct pal_min_state_area_s, pmsa_ifs)); + DEFINE(IA64_PMSA_XIP_OFFSET, + offsetof (struct pal_min_state_area_s, pmsa_xip)); + BLANK(); + /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr)); DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source)); diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 8d484204a3ff6..6dc726ad71372 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -48,6 +48,9 @@ * Delete dead variables and functions. * Reorder to remove the need for forward declarations and to consolidate * related code. + * + * 2005-08-12 Keith Owens <kaos@sgi.com> + * Convert MCA/INIT handlers to use per event stacks and SAL/OS state. */ #include <linux/config.h> #include <linux/types.h> @@ -77,6 +80,8 @@ #include <asm/irq.h> #include <asm/hw_irq.h> +#include "entry.h" + #if defined(IA64_MCA_DEBUG_INFO) # define IA64_MCA_DEBUG(fmt...) printk(fmt) #else @@ -84,9 +89,7 @@ #endif /* Used by mca_asm.S */ -ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; -ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state; -u64 ia64_mca_serialize; +u32 ia64_mca_serialize; DEFINE_PER_CPU(u64, ia64_mca_data); /* == __per_cpu_mca[smp_processor_id()] */ DEFINE_PER_CPU(u64, ia64_mca_per_cpu_pte); /* PTE to map per-CPU area */ DEFINE_PER_CPU(u64, ia64_mca_pal_pte); /* PTE to map PAL code */ @@ -95,8 +98,10 @@ DEFINE_PER_CPU(u64, ia64_mca_pal_base); /* vaddr PAL code granule */ unsigned long __per_cpu_mca[NR_CPUS]; /* In mca_asm.S */ -extern void ia64_monarch_init_handler (void); -extern void ia64_slave_init_handler (void); +extern void ia64_os_init_dispatch_monarch (void); +extern void ia64_os_init_dispatch_slave (void); + +static int monarch_cpu = -1; static ia64_mc_info_t ia64_mc_info; @@ -234,7 +239,8 @@ ia64_log_get(int sal_info_type, u8 **buffer, int irq_safe) * This function retrieves a specified error record type from SAL * and wakes up any processes waiting for error records. * - * Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT) + * Inputs : sal_info_type (Type of error record MCA/CMC/CPE) + * FIXME: remove MCA and irq_safe. */ static void ia64_mca_log_sal_error_record(int sal_info_type) @@ -242,7 +248,7 @@ ia64_mca_log_sal_error_record(int sal_info_type) u8 *buffer; sal_log_record_header_t *rh; u64 size; - int irq_safe = sal_info_type != SAL_INFO_TYPE_MCA && sal_info_type != SAL_INFO_TYPE_INIT; + int irq_safe = sal_info_type != SAL_INFO_TYPE_MCA; #ifdef IA64_MCA_DEBUG_INFO static const char * const rec_name[] = { "MCA", "INIT", "CMC", "CPE" }; #endif @@ -330,182 +336,6 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) #endif /* CONFIG_ACPI */ -static void -show_min_state (pal_min_state_area_t *minstate) -{ - u64 iip = minstate->pmsa_iip + ((struct ia64_psr *)(&minstate->pmsa_ipsr))->ri; - u64 xip = minstate->pmsa_xip + ((struct ia64_psr *)(&minstate->pmsa_xpsr))->ri; - - printk("NaT bits\t%016lx\n", minstate->pmsa_nat_bits); - printk("pr\t\t%016lx\n", minstate->pmsa_pr); - printk("b0\t\t%016lx ", minstate->pmsa_br0); print_symbol("%s\n", minstate->pmsa_br0); - printk("ar.rsc\t\t%016lx\n", minstate->pmsa_rsc); - printk("cr.iip\t\t%016lx ", iip); print_symbol("%s\n", iip); - printk("cr.ipsr\t\t%016lx\n", minstate->pmsa_ipsr); - printk("cr.ifs\t\t%016lx\n", minstate->pmsa_ifs); - printk("xip\t\t%016lx ", xip); print_symbol("%s\n", xip); - printk("xpsr\t\t%016lx\n", minstate->pmsa_xpsr); - printk("xfs\t\t%016lx\n", minstate->pmsa_xfs); - printk("b1\t\t%016lx ", minstate->pmsa_br1); - print_symbol("%s\n", minstate->pmsa_br1); - - printk("\nstatic registers r0-r15:\n"); - printk(" r0- 3 %016lx %016lx %016lx %016lx\n", - 0UL, minstate->pmsa_gr[0], minstate->pmsa_gr[1], minstate->pmsa_gr[2]); - printk(" r4- 7 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_gr[3], minstate->pmsa_gr[4], - minstate->pmsa_gr[5], minstate->pmsa_gr[6]); - printk(" r8-11 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_gr[7], minstate->pmsa_gr[8], - minstate->pmsa_gr[9], minstate->pmsa_gr[10]); - printk("r12-15 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_gr[11], minstate->pmsa_gr[12], - minstate->pmsa_gr[13], minstate->pmsa_gr[14]); - - printk("\nbank 0:\n"); - printk("r16-19 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_bank0_gr[0], minstate->pmsa_bank0_gr[1], - minstate->pmsa_bank0_gr[2], minstate->pmsa_bank0_gr[3]); - printk("r20-23 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_bank0_gr[4], minstate->pmsa_bank0_gr[5], - minstate->pmsa_bank0_gr[6], minstate->pmsa_bank0_gr[7]); - printk("r24-27 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_bank0_gr[8], minstate->pmsa_bank0_gr[9], - minstate->pmsa_bank0_gr[10], minstate->pmsa_bank0_gr[11]); - printk("r28-31 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_bank0_gr[12], minstate->pmsa_bank0_gr[13], - minstate->pmsa_bank0_gr[14], minstate->pmsa_bank0_gr[15]); - - printk("\nbank 1:\n"); - printk("r16-19 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_bank1_gr[0], minstate->pmsa_bank1_gr[1], - minstate->pmsa_bank1_gr[2], minstate->pmsa_bank1_gr[3]); - printk("r20-23 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_bank1_gr[4], minstate->pmsa_bank1_gr[5], - minstate->pmsa_bank1_gr[6], minstate->pmsa_bank1_gr[7]); - printk("r24-27 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_bank1_gr[8], minstate->pmsa_bank1_gr[9], - minstate->pmsa_bank1_gr[10], minstate->pmsa_bank1_gr[11]); - printk("r28-31 %016lx %016lx %016lx %016lx\n", - minstate->pmsa_bank1_gr[12], minstate->pmsa_bank1_gr[13], - minstate->pmsa_bank1_gr[14], minstate->pmsa_bank1_gr[15]); -} - -static void -fetch_min_state (pal_min_state_area_t *ms, struct pt_regs *pt, struct switch_stack *sw) -{ - u64 *dst_banked, *src_banked, bit, shift, nat_bits; - int i; - - /* - * First, update the pt-regs and switch-stack structures with the contents stored - * in the min-state area: - */ - if (((struct ia64_psr *) &ms->pmsa_ipsr)->ic == 0) { - pt->cr_ipsr = ms->pmsa_xpsr; - pt->cr_iip = ms->pmsa_xip; - pt->cr_ifs = ms->pmsa_xfs; - } else { - pt->cr_ipsr = ms->pmsa_ipsr; - pt->cr_iip = ms->pmsa_iip; - pt->cr_ifs = ms->pmsa_ifs; - } - pt->ar_rsc = ms->pmsa_rsc; - pt->pr = ms->pmsa_pr; - pt->r1 = ms->pmsa_gr[0]; - pt->r2 = ms->pmsa_gr[1]; - pt->r3 = ms->pmsa_gr[2]; - sw->r4 = ms->pmsa_gr[3]; - sw->r5 = ms->pmsa_gr[4]; - sw->r6 = ms->pmsa_gr[5]; - sw->r7 = ms->pmsa_gr[6]; - pt->r8 = ms->pmsa_gr[7]; - pt->r9 = ms->pmsa_gr[8]; - pt->r10 = ms->pmsa_gr[9]; - pt->r11 = ms->pmsa_gr[10]; - pt->r12 = ms->pmsa_gr[11]; - pt->r13 = ms->pmsa_gr[12]; - pt->r14 = ms->pmsa_gr[13]; - pt->r15 = ms->pmsa_gr[14]; - dst_banked = &pt->r16; /* r16-r31 are contiguous in struct pt_regs */ - src_banked = ms->pmsa_bank1_gr; - for (i = 0; i < 16; ++i) - dst_banked[i] = src_banked[i]; - pt->b0 = ms->pmsa_br0; - sw->b1 = ms->pmsa_br1; - - /* construct the NaT bits for the pt-regs structure: */ -# define PUT_NAT_BIT(dst, addr) \ - do { \ - bit = nat_bits & 1; nat_bits >>= 1; \ - shift = ((unsigned long) addr >> 3) & 0x3f; \ - dst = ((dst) & ~(1UL << shift)) | (bit << shift); \ - } while (0) - - /* Rotate the saved NaT bits such that bit 0 corresponds to pmsa_gr[0]: */ - shift = ((unsigned long) &ms->pmsa_gr[0] >> 3) & 0x3f; - nat_bits = (ms->pmsa_nat_bits >> shift) | (ms->pmsa_nat_bits << (64 - shift)); - - PUT_NAT_BIT(sw->caller_unat, &pt->r1); - PUT_NAT_BIT(sw->caller_unat, &pt->r2); - PUT_NAT_BIT(sw->caller_unat, &pt->r3); - PUT_NAT_BIT(sw->ar_unat, &sw->r4); - PUT_NAT_BIT(sw->ar_unat, &sw->r5); - PUT_NAT_BIT(sw->ar_unat, &sw->r6); - PUT_NAT_BIT(sw->ar_unat, &sw->r7); - PUT_NAT_BIT(sw->caller_unat, &pt->r8); PUT_NAT_BIT(sw->caller_unat, &pt->r9); - PUT_NAT_BIT(sw->caller_unat, &pt->r10); PUT_NAT_BIT(sw->caller_unat, &pt->r11); - PUT_NAT_BIT(sw->caller_unat, &pt->r12); PUT_NAT_BIT(sw->caller_unat, &pt->r13); - PUT_NAT_BIT(sw->caller_unat, &pt->r14); PUT_NAT_BIT(sw->caller_unat, &pt->r15); - nat_bits >>= 16; /* skip over bank0 NaT bits */ - PUT_NAT_BIT(sw->caller_unat, &pt->r16); PUT_NAT_BIT(sw->caller_unat, &pt->r17); - PUT_NAT_BIT(sw->caller_unat, &pt->r18); PUT_NAT_BIT(sw->caller_unat, &pt->r19); - PUT_NAT_BIT(sw->caller_unat, &pt->r20); PUT_NAT_BIT(sw->caller_unat, &pt->r21); - PUT_NAT_BIT(sw->caller_unat, &pt->r22); PUT_NAT_BIT(sw->caller_unat, &pt->r23); - PUT_NAT_BIT(sw->caller_unat, &pt->r24); PUT_NAT_BIT(sw->caller_unat, &pt->r25); - PUT_NAT_BIT(sw->caller_unat, &pt->r26); PUT_NAT_BIT(sw->caller_unat, &pt->r27); - PUT_NAT_BIT(sw->caller_unat, &pt->r28); PUT_NAT_BIT(sw->caller_unat, &pt->r29); - PUT_NAT_BIT(sw->caller_unat, &pt->r30); PUT_NAT_BIT(sw->caller_unat, &pt->r31); -} - -static void -init_handler_platform (pal_min_state_area_t *ms, - struct pt_regs *pt, struct switch_stack *sw) -{ - struct unw_frame_info info; - - /* if a kernel debugger is available call it here else just dump the registers */ - - /* - * Wait for a bit. On some machines (e.g., HP's zx2000 and zx6000, INIT can be - * generated via the BMC's command-line interface, but since the console is on the - * same serial line, the user will need some time to switch out of the BMC before - * the dump begins. - */ - printk("Delaying for 5 seconds...\n"); - udelay(5*1000000); - show_min_state(ms); - - printk("Backtrace of current task (pid %d, %s)\n", current->pid, current->comm); - fetch_min_state(ms, pt, sw); - unw_init_from_interruption(&info, current, pt, sw); - ia64_do_show_stack(&info, NULL); - - if (read_trylock(&tasklist_lock)) { - struct task_struct *g, *t; - do_each_thread (g, t) { - if (t == current) - continue; - - printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm); - show_stack(t, NULL); - } while_each_thread (g, t); - } - - printk("\nINIT dump complete. Please reboot now.\n"); - while (1); /* hang city if no debugger */ -} - #ifdef CONFIG_ACPI /* * ia64_mca_register_cpev @@ -647,42 +477,6 @@ ia64_mca_cmc_vector_enable_keventd(void *unused) on_each_cpu(ia64_mca_cmc_vector_enable, NULL, 1, 0); } -/* - * ia64_mca_wakeup_ipi_wait - * - * Wait for the inter-cpu interrupt to be sent by the - * monarch processor once it is done with handling the - * MCA. - * - * Inputs : None - * Outputs : None - */ -static void -ia64_mca_wakeup_ipi_wait(void) -{ - int irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6); - int irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f); - u64 irr = 0; - - do { - switch(irr_num) { - case 0: - irr = ia64_getreg(_IA64_REG_CR_IRR0); - break; - case 1: - irr = ia64_getreg(_IA64_REG_CR_IRR1); - break; - case 2: - irr = ia64_getreg(_IA64_REG_CR_IRR2); - break; - case 3: - irr = ia64_getreg(_IA64_REG_CR_IRR3); - break; - } - cpu_relax(); - } while (!(irr & (1UL << irr_bit))) ; -} - /* * ia64_mca_wakeup * @@ -748,11 +542,9 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) */ ia64_sal_mc_rendez(); - /* Wait for the wakeup IPI from the monarch - * This waiting is done by polling on the wakeup-interrupt - * vector bit in the processor's IRRs - */ - ia64_mca_wakeup_ipi_wait(); + /* Wait for the monarch cpu to exit. */ + while (monarch_cpu != -1) + cpu_relax(); /* spin until monarch leaves */ /* Enable all interrupts */ local_irq_restore(flags); @@ -780,53 +572,13 @@ ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs) return IRQ_HANDLED; } -/* - * ia64_return_to_sal_check - * - * This is function called before going back from the OS_MCA handler - * to the OS_MCA dispatch code which finally takes the control back - * to the SAL. - * The main purpose of this routine is to setup the OS_MCA to SAL - * return state which can be used by the OS_MCA dispatch code - * just before going back to SAL. - * - * Inputs : None - * Outputs : None - */ - -static void -ia64_return_to_sal_check(int recover) -{ - - /* Copy over some relevant stuff from the sal_to_os_mca_handoff - * so that it can be used at the time of os_mca_to_sal_handoff - */ - ia64_os_to_sal_handoff_state.imots_sal_gp = - ia64_sal_to_os_handoff_state.imsto_sal_gp; - - ia64_os_to_sal_handoff_state.imots_sal_check_ra = - ia64_sal_to_os_handoff_state.imsto_sal_check_ra; - - if (recover) - ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; - else - ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; - - /* Default = tell SAL to return to same context */ - ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT; - - ia64_os_to_sal_handoff_state.imots_new_min_state = - (u64 *)ia64_sal_to_os_handoff_state.pal_min_state; - -} - /* Function pointer for extra MCA recovery */ int (*ia64_mca_ucmc_extension) - (void*,ia64_mca_sal_to_os_state_t*,ia64_mca_os_to_sal_state_t*) + (void*,struct ia64_sal_os_state*) = NULL; int -ia64_reg_MCA_extension(void *fn) +ia64_reg_MCA_extension(int (*fn)(void *, struct ia64_sal_os_state *)) { if (ia64_mca_ucmc_extension) return 1; @@ -845,8 +597,321 @@ ia64_unreg_MCA_extension(void) EXPORT_SYMBOL(ia64_reg_MCA_extension); EXPORT_SYMBOL(ia64_unreg_MCA_extension); + +static inline void +copy_reg(const u64 *fr, u64 fnat, u64 *tr, u64 *tnat) +{ + u64 fslot, tslot, nat; + *tr = *fr; + fslot = ((unsigned long)fr >> 3) & 63; + tslot = ((unsigned long)tr >> 3) & 63; + *tnat &= ~(1UL << tslot); + nat = (fnat >> fslot) & 1; + *tnat |= (nat << tslot); +} + +/* On entry to this routine, we are running on the per cpu stack, see + * mca_asm.h. The original stack has not been touched by this event. Some of + * the original stack's registers will be in the RBS on this stack. This stack + * also contains a partial pt_regs and switch_stack, the rest of the data is in + * PAL minstate. + * + * The first thing to do is modify the original stack to look like a blocked + * task so we can run backtrace on the original task. Also mark the per cpu + * stack as current to ensure that we use the correct task state, it also means + * that we can do backtrace on the MCA/INIT handler code itself. + */ + +static task_t * +ia64_mca_modify_original_stack(struct pt_regs *regs, + const struct switch_stack *sw, + struct ia64_sal_os_state *sos, + const char *type) +{ + char *p, comm[sizeof(current->comm)]; + ia64_va va; + extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */ + const pal_min_state_area_t *ms = sos->pal_min_state; + task_t *previous_current; + struct pt_regs *old_regs; + struct switch_stack *old_sw; + unsigned size = sizeof(struct pt_regs) + + sizeof(struct switch_stack) + 16; + u64 *old_bspstore, *old_bsp; + u64 *new_bspstore, *new_bsp; + u64 old_unat, old_rnat, new_rnat, nat; + u64 slots, loadrs = regs->loadrs; + u64 r12 = ms->pmsa_gr[12-1], r13 = ms->pmsa_gr[13-1]; + u64 ar_bspstore = regs->ar_bspstore; + u64 ar_bsp = regs->ar_bspstore + (loadrs >> 16); + const u64 *bank; + const char *msg; + int cpu = smp_processor_id(); + + previous_current = curr_task(cpu); + set_curr_task(cpu, current); + if ((p = strchr(current->comm, ' '))) + *p = '\0'; + + /* Best effort attempt to cope with MCA/INIT delivered while in + * physical mode. + */ + regs->cr_ipsr = ms->pmsa_ipsr; + if (ia64_psr(regs)->dt == 0) { + va.l = r12; + if (va.f.reg == 0) { + va.f.reg = 7; + r12 = va.l; + } + va.l = r13; + if (va.f.reg == 0) { + va.f.reg = 7; + r13 = va.l; + } + } + if (ia64_psr(regs)->rt == 0) { + va.l = ar_bspstore; + if (va.f.reg == 0) { + va.f.reg = 7; + ar_bspstore = va.l; + } + va.l = ar_bsp; + if (va.f.reg == 0) { + va.f.reg = 7; + ar_bsp = va.l; + } + } + + /* mca_asm.S ia64_old_stack() cannot assume that the dirty registers + * have been copied to the old stack, the old stack may fail the + * validation tests below. So ia64_old_stack() must restore the dirty + * registers from the new stack. The old and new bspstore probably + * have different alignments, so loadrs calculated on the old bsp + * cannot be used to restore from the new bsp. Calculate a suitable + * loadrs for the new stack and save it in the new pt_regs, where + * ia64_old_stack() can get it. + */ + old_bspstore = (u64 *)ar_bspstore; + old_bsp = (u64 *)ar_bsp; + slots = ia64_rse_num_regs(old_bspstore, old_bsp); + new_bspstore = (u64 *)((u64)current + IA64_RBS_OFFSET); + new_bsp = ia64_rse_skip_regs(new_bspstore, slots); + regs->loadrs = (new_bsp - new_bspstore) * 8 << 16; + + /* Verify the previous stack state before we change it */ + if (user_mode(regs)) { + msg = "occurred in user space"; + goto no_mod; + } + if (r13 != sos->prev_IA64_KR_CURRENT) { + msg = "inconsistent previous current and r13"; + goto no_mod; + } + if ((r12 - r13) >= KERNEL_STACK_SIZE) { + msg = "inconsistent r12 and r13"; + goto no_mod; + } + if ((ar_bspstore - r13) >= KERNEL_STACK_SIZE) { + msg = "inconsistent ar.bspstore and r13"; + goto no_mod; + } + va.p = old_bspstore; + if (va.f.reg < 5) { + msg = "old_bspstore is in the wrong region"; + goto no_mod; + } + if ((ar_bsp - r13) >= KERNEL_STACK_SIZE) { + msg = "inconsistent ar.bsp and r13"; + goto no_mod; + } + size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8; + if (ar_bspstore + size > r12) { + msg = "no room for blocked state"; + goto no_mod; + } + + /* Change the comm field on the MCA/INT task to include the pid that + * was interrupted, it makes for easier debugging. If that pid was 0 + * (swapper or nested MCA/INIT) then use the start of the previous comm + * field suffixed with its cpu. + */ + if (previous_current->pid) + snprintf(comm, sizeof(comm), "%s %d", + current->comm, previous_current->pid); + else { + int l; + if ((p = strchr(previous_current->comm, ' '))) + l = p - previous_current->comm; + else + l = strlen(previous_current->comm); + snprintf(comm, sizeof(comm), "%s %*s %d", + current->comm, l, previous_current->comm, + previous_current->thread_info->cpu); + } + memcpy(current->comm, comm, sizeof(current->comm)); + + /* Make the original task look blocked. First stack a struct pt_regs, + * describing the state at the time of interrupt. mca_asm.S built a + * partial pt_regs, copy it and fill in the blanks using minstate. + */ + p = (char *)r12 - sizeof(*regs); + old_regs = (struct pt_regs *)p; + memcpy(old_regs, regs, sizeof(*regs)); + /* If ipsr.ic then use pmsa_{iip,ipsr,ifs}, else use + * pmsa_{xip,xpsr,xfs} + */ + if (ia64_psr(regs)->ic) { + old_regs->cr_iip = ms->pmsa_iip; + old_regs->cr_ipsr = ms->pmsa_ipsr; + old_regs->cr_ifs = ms->pmsa_ifs; + } else { + old_regs->cr_iip = ms->pmsa_xip; + old_regs->cr_ipsr = ms->pmsa_xpsr; + old_regs->cr_ifs = ms->pmsa_xfs; + } + old_regs->pr = ms->pmsa_pr; + old_regs->b0 = ms->pmsa_br0; + old_regs->loadrs = loadrs; + old_regs->ar_rsc = ms->pmsa_rsc; + old_unat = old_regs->ar_unat; + copy_reg(&ms->pmsa_gr[1-1], ms->pmsa_nat_bits, &old_regs->r1, &old_unat); + copy_reg(&ms->pmsa_gr[2-1], ms->pmsa_nat_bits, &old_regs->r2, &old_unat); + copy_reg(&ms->pmsa_gr[3-1], ms->pmsa_nat_bits, &old_regs->r3, &old_unat); + copy_reg(&ms->pmsa_gr[8-1], ms->pmsa_nat_bits, &old_regs->r8, &old_unat); + copy_reg(&ms->pmsa_gr[9-1], ms->pmsa_nat_bits, &old_regs->r9, &old_unat); + copy_reg(&ms->pmsa_gr[10-1], ms->pmsa_nat_bits, &old_regs->r10, &old_unat); + copy_reg(&ms->pmsa_gr[11-1], ms->pmsa_nat_bits, &old_regs->r11, &old_unat); + copy_reg(&ms->pmsa_gr[12-1], ms->pmsa_nat_bits, &old_regs->r12, &old_unat); + copy_reg(&ms->pmsa_gr[13-1], ms->pmsa_nat_bits, &old_regs->r13, &old_unat); + copy_reg(&ms->pmsa_gr[14-1], ms->pmsa_nat_bits, &old_regs->r14, &old_unat); + copy_reg(&ms->pmsa_gr[15-1], ms->pmsa_nat_bits, &old_regs->r15, &old_unat); + if (ia64_psr(old_regs)->bn) + bank = ms->pmsa_bank1_gr; + else + bank = ms->pmsa_bank0_gr; + copy_reg(&bank[16-16], ms->pmsa_nat_bits, &old_regs->r16, &old_unat); + copy_reg(&bank[17-16], ms->pmsa_nat_bits, &old_regs->r17, &old_unat); + copy_reg(&bank[18-16], ms->pmsa_nat_bits, &old_regs->r18, &old_unat); + copy_reg(&bank[19-16], ms->pmsa_nat_bits, &old_regs->r19, &old_unat); + copy_reg(&bank[20-16], ms->pmsa_nat_bits, &old_regs->r20, &old_unat); + copy_reg(&bank[21-16], ms->pmsa_nat_bits, &old_regs->r21, &old_unat); + copy_reg(&bank[22-16], ms->pmsa_nat_bits, &old_regs->r22, &old_unat); + copy_reg(&bank[23-16], ms->pmsa_nat_bits, &old_regs->r23, &old_unat); + copy_reg(&bank[24-16], ms->pmsa_nat_bits, &old_regs->r24, &old_unat); + copy_reg(&bank[25-16], ms->pmsa_nat_bits, &old_regs->r25, &old_unat); + copy_reg(&bank[26-16], ms->pmsa_nat_bits, &old_regs->r26, &old_unat); + copy_reg(&bank[27-16], ms->pmsa_nat_bits, &old_regs->r27, &old_unat); + copy_reg(&bank[28-16], ms->pmsa_nat_bits, &old_regs->r28, &old_unat); + copy_reg(&bank[29-16], ms->pmsa_nat_bits, &old_regs->r29, &old_unat); + copy_reg(&bank[30-16], ms->pmsa_nat_bits, &old_regs->r30, &old_unat); + copy_reg(&bank[31-16], ms->pmsa_nat_bits, &old_regs->r31, &old_unat); + + /* Next stack a struct switch_stack. mca_asm.S built a partial + * switch_stack, copy it and fill in the blanks using pt_regs and + * minstate. + * + * In the synthesized switch_stack, b0 points to ia64_leave_kernel, + * ar.pfs is set to 0. + * + * unwind.c::unw_unwind() does special processing for interrupt frames. + * It checks if the PRED_NON_SYSCALL predicate is set, if the predicate + * is clear then unw_unwind() does _not_ adjust bsp over pt_regs. Not + * that this is documented, of course. Set PRED_NON_SYSCALL in the + * switch_stack on the original stack so it will unwind correctly when + * unwind.c reads pt_regs. + * + * thread.ksp is updated to point to the synthesized switch_stack. + */ + p -= sizeof(struct switch_stack); + old_sw = (struct switch_stack *)p; + memcpy(old_sw, sw, sizeof(*sw)); + old_sw->caller_unat = old_unat; + old_sw->ar_fpsr = old_regs->ar_fpsr; + copy_reg(&ms->pmsa_gr[4-1], ms->pmsa_nat_bits, &old_sw->r4, &old_unat); + copy_reg(&ms->pmsa_gr[5-1], ms->pmsa_nat_bits, &old_sw->r5, &old_unat); + copy_reg(&ms->pmsa_gr[6-1], ms->pmsa_nat_bits, &old_sw->r6, &old_unat); + copy_reg(&ms->pmsa_gr[7-1], ms->pmsa_nat_bits, &old_sw->r7, &old_unat); + old_sw->b0 = (u64)ia64_leave_kernel; + old_sw->b1 = ms->pmsa_br1; + old_sw->ar_pfs = 0; + old_sw->ar_unat = old_unat; + old_sw->pr = old_regs->pr | (1UL << PRED_NON_SYSCALL); + previous_current->thread.ksp = (u64)p - 16; + + /* Finally copy the original stack's registers back to its RBS. + * Registers from ar.bspstore through ar.bsp at the time of the event + * are in the current RBS, copy them back to the original stack. The + * copy must be done register by register because the original bspstore + * and the current one have different alignments, so the saved RNAT + * data occurs at different places. + * + * mca_asm does cover, so the old_bsp already includes all registers at + * the time of MCA/INIT. It also does flushrs, so all registers before + * this function have been written to backing store on the MCA/INIT + * stack. + */ + new_rnat = ia64_get_rnat(ia64_rse_rnat_addr(new_bspstore)); + old_rnat = regs->ar_rnat; + while (slots--) { + if (ia64_rse_is_rnat_slot(new_bspstore)) { + new_rnat = ia64_get_rnat(new_bspstore++); + } + if (ia64_rse_is_rnat_slot(old_bspstore)) { + *old_bspstore++ = old_rnat; + old_rnat = 0; + } + nat = (new_rnat >> ia64_rse_slot_num(new_bspstore)) & 1UL; + old_rnat &= ~(1UL << ia64_rse_slot_num(old_bspstore)); + old_rnat |= (nat << ia64_rse_slot_num(old_bspstore)); + *old_bspstore++ = *new_bspstore++; + } + old_sw->ar_bspstore = (unsigned long)old_bspstore; + old_sw->ar_rnat = old_rnat; + + sos->prev_task = previous_current; + return previous_current; + +no_mod: + printk(KERN_INFO "cpu %d, %s %s, original stack not modified\n", + smp_processor_id(), type, msg); + return previous_current; +} + +/* The monarch/slave interaction is based on monarch_cpu and requires that all + * slaves have entered rendezvous before the monarch leaves. If any cpu has + * not entered rendezvous yet then wait a bit. The assumption is that any + * slave that has not rendezvoused after a reasonable time is never going to do + * so. In this context, slave includes cpus that respond to the MCA rendezvous + * interrupt, as well as cpus that receive the INIT slave event. + */ + +static void +ia64_wait_for_slaves(int monarch) +{ + int c, wait = 0; + for_each_online_cpu(c) { + if (c == monarch) + continue; + if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) { + udelay(1000); /* short wait first */ + wait = 1; + break; + } + } + if (!wait) + return; + for_each_online_cpu(c) { + if (c == monarch) + continue; + if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) { + udelay(5*1000000); /* wait 5 seconds for slaves (arbitrary) */ + break; + } + } +} + /* - * ia64_mca_ucmc_handler + * ia64_mca_handler * * This is uncorrectable machine check handler called from OS_MCA * dispatch code which is in turn called from SAL_CHECK(). @@ -857,16 +922,28 @@ EXPORT_SYMBOL(ia64_unreg_MCA_extension); * further MCA logging is enabled by clearing logs. * Monarch also has the duty of sending wakeup-IPIs to pull the * slave processors out of rendezvous spinloop. - * - * Inputs : None - * Outputs : None */ void -ia64_mca_ucmc_handler(void) +ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, + struct ia64_sal_os_state *sos) { pal_processor_state_info_t *psp = (pal_processor_state_info_t *) - &ia64_sal_to_os_handoff_state.proc_state_param; - int recover; + &sos->proc_state_param; + int recover, cpu = smp_processor_id(); + task_t *previous_current; + + oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ + previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); + monarch_cpu = cpu; + ia64_wait_for_slaves(cpu); + + /* Wakeup all the processors which are spinning in the rendezvous loop. + * They will leave SAL, then spin in the OS with interrupts disabled + * until this monarch cpu leaves the MCA handler. That gets control + * back to the OS so we can backtrace the other cpus, backtrace when + * spinning in SAL does not work. + */ + ia64_mca_wakeup_all(); /* Get the MCA error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); @@ -874,25 +951,20 @@ ia64_mca_ucmc_handler(void) /* TLB error is only exist in this SAL error record */ recover = (psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc)) /* other error recovery */ - || (ia64_mca_ucmc_extension + || (ia64_mca_ucmc_extension && ia64_mca_ucmc_extension( IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA), - &ia64_sal_to_os_handoff_state, - &ia64_os_to_sal_handoff_state)); + sos)); if (recover) { sal_log_record_header_t *rh = IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA); rh->severity = sal_log_severity_corrected; ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); + sos->os_status = IA64_MCA_CORRECTED; } - /* - * Wakeup all the processors which are spinning in the rendezvous - * loop. - */ - ia64_mca_wakeup_all(); - /* Return to SAL */ - ia64_return_to_sal_check(recover); + set_curr_task(cpu, previous_current); + monarch_cpu = -1; } static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd, NULL); @@ -1116,34 +1188,114 @@ ia64_mca_cpe_poll (unsigned long dummy) /* * C portion of the OS INIT handler * - * Called from ia64_monarch_init_handler - * - * Inputs: pointer to pt_regs where processor info was saved. + * Called from ia64_os_init_dispatch * - * Returns: - * 0 if SAL must warm boot the System - * 1 if SAL must return to interrupted context using PAL_MC_RESUME + * Inputs: pointer to pt_regs where processor info was saved. SAL/OS state for + * this event. This code is used for both monarch and slave INIT events, see + * sos->monarch. * + * All INIT events switch to the INIT stack and change the previous process to + * blocked status. If one of the INIT events is the monarch then we are + * probably processing the nmi button/command. Use the monarch cpu to dump all + * the processes. The slave INIT events all spin until the monarch cpu + * returns. We can also get INIT slave events for MCA, in which case the MCA + * process is the monarch. */ + void -ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) +ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, + struct ia64_sal_os_state *sos) { - pal_min_state_area_t *ms; + static atomic_t slaves; + static atomic_t monarchs; + task_t *previous_current; + int cpu = smp_processor_id(), c; + struct task_struct *g, *t; - oops_in_progress = 1; /* avoid deadlock in printk, but it makes recovery dodgy */ + oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ console_loglevel = 15; /* make sure printks make it to console */ - printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n", - ia64_sal_to_os_handoff_state.proc_state_param); + printk(KERN_INFO "Entered OS INIT handler. PSP=%lx cpu=%d monarch=%ld\n", + sos->proc_state_param, cpu, sos->monarch); + salinfo_log_wakeup(SAL_INFO_TYPE_INIT, NULL, 0, 0); - /* - * Address of minstate area provided by PAL is physical, - * uncacheable (bit 63 set). Convert to Linux virtual - * address in region 6. + previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "INIT"); + sos->os_status = IA64_INIT_RESUME; + + /* FIXME: Workaround for broken proms that drive all INIT events as + * slaves. The last slave that enters is promoted to be a monarch. + * Remove this code in September 2006, that gives platforms a year to + * fix their proms and get their customers updated. */ - ms = (pal_min_state_area_t *)(ia64_sal_to_os_handoff_state.pal_min_state | (6ul<<61)); + if (!sos->monarch && atomic_add_return(1, &slaves) == num_online_cpus()) { + printk(KERN_WARNING "%s: Promoting cpu %d to monarch.\n", + __FUNCTION__, cpu); + atomic_dec(&slaves); + sos->monarch = 1; + } - init_handler_platform(ms, pt, sw); /* call platform specific routines */ + /* FIXME: Workaround for broken proms that drive all INIT events as + * monarchs. Second and subsequent monarchs are demoted to slaves. + * Remove this code in September 2006, that gives platforms a year to + * fix their proms and get their customers updated. + */ + if (sos->monarch && atomic_add_return(1, &monarchs) > 1) { + printk(KERN_WARNING "%s: Demoting cpu %d to slave.\n", + __FUNCTION__, cpu); + atomic_dec(&monarchs); + sos->monarch = 0; + } + + if (!sos->monarch) { + ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_INIT; + while (monarch_cpu == -1) + cpu_relax(); /* spin until monarch enters */ + while (monarch_cpu != -1) + cpu_relax(); /* spin until monarch leaves */ + printk("Slave on cpu %d returning to normal service.\n", cpu); + set_curr_task(cpu, previous_current); + ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; + atomic_dec(&slaves); + return; + } + + monarch_cpu = cpu; + + /* + * Wait for a bit. On some machines (e.g., HP's zx2000 and zx6000, INIT can be + * generated via the BMC's command-line interface, but since the console is on the + * same serial line, the user will need some time to switch out of the BMC before + * the dump begins. + */ + printk("Delaying for 5 seconds...\n"); + udelay(5*1000000); + ia64_wait_for_slaves(cpu); + printk(KERN_ERR "Processes interrupted by INIT -"); + for_each_online_cpu(c) { + struct ia64_sal_os_state *s; + t = __va(__per_cpu_mca[c] + IA64_MCA_CPU_INIT_STACK_OFFSET); + s = (struct ia64_sal_os_state *)((char *)t + MCA_SOS_OFFSET); + g = s->prev_task; + if (g) { + if (g->pid) + printk(" %d", g->pid); + else + printk(" %d (cpu %d task 0x%p)", g->pid, task_cpu(g), g); + } + } + printk("\n\n"); + if (read_trylock(&tasklist_lock)) { + do_each_thread (g, t) { + printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm); + show_stack(t, NULL); + } while_each_thread (g, t); + read_unlock(&tasklist_lock); + } + printk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu); + atomic_dec(&monarchs); + set_curr_task(cpu, previous_current); + monarch_cpu = -1; + return; } static int __init @@ -1193,6 +1345,34 @@ static struct irqaction mca_cpep_irqaction = { }; #endif /* CONFIG_ACPI */ +/* Minimal format of the MCA/INIT stacks. The pseudo processes that run on + * these stacks can never sleep, they cannot return from the kernel to user + * space, they do not appear in a normal ps listing. So there is no need to + * format most of the fields. + */ + +static void +format_mca_init_stack(void *mca_data, unsigned long offset, + const char *type, int cpu) +{ + struct task_struct *p = (struct task_struct *)((char *)mca_data + offset); + struct thread_info *ti; + memset(p, 0, KERNEL_STACK_SIZE); + ti = (struct thread_info *)((char *)p + IA64_TASK_SIZE); + ti->flags = _TIF_MCA_INIT; + ti->preempt_count = 1; + ti->task = p; + ti->cpu = cpu; + p->thread_info = ti; + p->state = TASK_UNINTERRUPTIBLE; + __set_bit(cpu, &p->cpus_allowed); + INIT_LIST_HEAD(&p->tasks); + p->parent = p->real_parent = p->group_leader = p; + INIT_LIST_HEAD(&p->children); + INIT_LIST_HEAD(&p->sibling); + strncpy(p->comm, type, sizeof(p->comm)-1); +} + /* Do per-CPU MCA-related initialization. */ void __devinit @@ -1205,19 +1385,28 @@ ia64_mca_cpu_init(void *cpu_data) int cpu; mca_data = alloc_bootmem(sizeof(struct ia64_mca_cpu) - * NR_CPUS); + * NR_CPUS + KERNEL_STACK_SIZE); + mca_data = (void *)(((unsigned long)mca_data + + KERNEL_STACK_SIZE - 1) & + (-KERNEL_STACK_SIZE)); for (cpu = 0; cpu < NR_CPUS; cpu++) { + format_mca_init_stack(mca_data, + offsetof(struct ia64_mca_cpu, mca_stack), + "MCA", cpu); + format_mca_init_stack(mca_data, + offsetof(struct ia64_mca_cpu, init_stack), + "INIT", cpu); __per_cpu_mca[cpu] = __pa(mca_data); mca_data += sizeof(struct ia64_mca_cpu); } } - /* - * The MCA info structure was allocated earlier and its - * physical address saved in __per_cpu_mca[cpu]. Copy that - * address * to ia64_mca_data so we can access it as a per-CPU - * variable. - */ + /* + * The MCA info structure was allocated earlier and its + * physical address saved in __per_cpu_mca[cpu]. Copy that + * address * to ia64_mca_data so we can access it as a per-CPU + * variable. + */ __get_cpu_var(ia64_mca_data) = __per_cpu_mca[smp_processor_id()]; /* @@ -1227,11 +1416,11 @@ ia64_mca_cpu_init(void *cpu_data) __get_cpu_var(ia64_mca_per_cpu_pte) = pte_val(mk_pte_phys(__pa(cpu_data), PAGE_KERNEL)); - /* - * Also, stash away a copy of the PAL address and the PTE - * needed to map it. - */ - pal_vaddr = efi_get_pal_addr(); + /* + * Also, stash away a copy of the PAL address and the PTE + * needed to map it. + */ + pal_vaddr = efi_get_pal_addr(); if (!pal_vaddr) return; __get_cpu_var(ia64_mca_pal_base) = @@ -1263,8 +1452,8 @@ ia64_mca_cpu_init(void *cpu_data) void __init ia64_mca_init(void) { - ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; - ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; + ia64_fptr_t *init_hldlr_ptr_monarch = (ia64_fptr_t *)ia64_os_init_dispatch_monarch; + ia64_fptr_t *init_hldlr_ptr_slave = (ia64_fptr_t *)ia64_os_init_dispatch_slave; ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; int i; s64 rc; @@ -1342,9 +1531,9 @@ ia64_mca_init(void) * XXX - disable SAL checksum by setting size to 0, should be * size of the actual init handler in mca_asm.S. */ - ia64_mc_info.imi_monarch_init_handler = ia64_tpa(mon_init_ptr->fp); + ia64_mc_info.imi_monarch_init_handler = ia64_tpa(init_hldlr_ptr_monarch->fp); ia64_mc_info.imi_monarch_init_handler_size = 0; - ia64_mc_info.imi_slave_init_handler = ia64_tpa(slave_init_ptr->fp); + ia64_mc_info.imi_slave_init_handler = ia64_tpa(init_hldlr_ptr_slave->fp); ia64_mc_info.imi_slave_init_handler_size = 0; IA64_MCA_DEBUG("%s: OS INIT handler at %lx\n", __FUNCTION__, diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S index ef3fd7265b67c..499a065f4e601 100644 --- a/arch/ia64/kernel/mca_asm.S +++ b/arch/ia64/kernel/mca_asm.S @@ -16,6 +16,9 @@ // 04/11/12 Russ Anderson <rja@sgi.com> // Added per cpu MCA/INIT stack save areas. // +// 12/08/05 Keith Owens <kaos@sgi.com> +// Use per cpu MCA/INIT stacks for all data. +// #include <linux/config.h> #include <linux/threads.h> @@ -25,96 +28,23 @@ #include <asm/mca_asm.h> #include <asm/mca.h> -/* - * When we get a machine check, the kernel stack pointer is no longer - * valid, so we need to set a new stack pointer. - */ -#define MINSTATE_PHYS /* Make sure stack access is physical for MINSTATE */ - -/* - * Needed for return context to SAL - */ -#define IA64_MCA_SAME_CONTEXT 0 -#define IA64_MCA_COLD_BOOT -2 - -#include "minstate.h" - -/* - * SAL_TO_OS_MCA_HANDOFF_STATE (SAL 3.0 spec) - * 1. GR1 = OS GP - * 2. GR8 = PAL_PROC physical address - * 3. GR9 = SAL_PROC physical address - * 4. GR10 = SAL GP (physical) - * 5. GR11 = Rendez state - * 6. GR12 = Return address to location within SAL_CHECK - */ -#define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ - LOAD_PHYSICAL(p0, _tmp, ia64_sal_to_os_handoff_state);; \ - st8 [_tmp]=r1,0x08;; \ - st8 [_tmp]=r8,0x08;; \ - st8 [_tmp]=r9,0x08;; \ - st8 [_tmp]=r10,0x08;; \ - st8 [_tmp]=r11,0x08;; \ - st8 [_tmp]=r12,0x08;; \ - st8 [_tmp]=r17,0x08;; \ - st8 [_tmp]=r18,0x08 - -/* - * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec) - * (p6) is executed if we never entered virtual mode (TLB error) - * (p7) is executed if we entered virtual mode as expected (normal case) - * 1. GR8 = OS_MCA return status - * 2. GR9 = SAL GP (physical) - * 3. GR10 = 0/1 returning same/new context - * 4. GR22 = New min state save area pointer - * returns ptr to SAL rtn save loc in _tmp - */ -#define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ - movl _tmp=ia64_os_to_sal_handoff_state;; \ - DATA_VA_TO_PA(_tmp);; \ - ld8 r8=[_tmp],0x08;; \ - ld8 r9=[_tmp],0x08;; \ - ld8 r10=[_tmp],0x08;; \ - ld8 r22=[_tmp],0x08;; - // now _tmp is pointing to SAL rtn save location - -/* - * COLD_BOOT_HANDOFF_STATE() sets ia64_mca_os_to_sal_state - * imots_os_status=IA64_MCA_COLD_BOOT - * imots_sal_gp=SAL GP - * imots_context=IA64_MCA_SAME_CONTEXT - * imots_new_min_state=Min state save area pointer - * imots_sal_check_ra=Return address to location within SAL_CHECK - * - */ -#define COLD_BOOT_HANDOFF_STATE(sal_to_os_handoff,os_to_sal_handoff,tmp)\ - movl tmp=IA64_MCA_COLD_BOOT; \ - movl sal_to_os_handoff=__pa(ia64_sal_to_os_handoff_state); \ - movl os_to_sal_handoff=__pa(ia64_os_to_sal_handoff_state);; \ - st8 [os_to_sal_handoff]=tmp,8;; \ - ld8 tmp=[sal_to_os_handoff],48;; \ - st8 [os_to_sal_handoff]=tmp,8;; \ - movl tmp=IA64_MCA_SAME_CONTEXT;; \ - st8 [os_to_sal_handoff]=tmp,8;; \ - ld8 tmp=[sal_to_os_handoff],-8;; \ - st8 [os_to_sal_handoff]=tmp,8;; \ - ld8 tmp=[sal_to_os_handoff];; \ - st8 [os_to_sal_handoff]=tmp;; +#include "entry.h" #define GET_IA64_MCA_DATA(reg) \ GET_THIS_PADDR(reg, ia64_mca_data) \ ;; \ ld8 reg=[reg] - .global ia64_os_mca_dispatch - .global ia64_os_mca_dispatch_end - .global ia64_sal_to_os_handoff_state - .global ia64_os_to_sal_handoff_state .global ia64_do_tlb_purge + .global ia64_os_mca_dispatch + .global ia64_os_init_dispatch_monarch + .global ia64_os_init_dispatch_slave .text .align 16 +//StartMain//////////////////////////////////////////////////////////////////// + /* * Just the TLB purge part is moved to a separate function * so we can re-use the code for cpu hotplug code as well @@ -207,34 +137,31 @@ ia64_do_tlb_purge: br.sptk.many b1 ;; -ia64_os_mca_dispatch: +//EndMain////////////////////////////////////////////////////////////////////// + +//StartMain//////////////////////////////////////////////////////////////////// +ia64_os_mca_dispatch: // Serialize all MCA processing mov r3=1;; LOAD_PHYSICAL(p0,r2,ia64_mca_serialize);; ia64_os_mca_spin: - xchg8 r4=[r2],r3;; + xchg4 r4=[r2],r3;; cmp.ne p6,p0=r4,r0 (p6) br ia64_os_mca_spin - // Save the SAL to OS MCA handoff state as defined - // by SAL SPEC 3.0 - // NOTE : The order in which the state gets saved - // is dependent on the way the C-structure - // for ia64_mca_sal_to_os_state_t has been - // defined in include/asm/mca.h - SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2) - ;; - - // LOG PROCESSOR STATE INFO FROM HERE ON.. -begin_os_mca_dump: - br ia64_os_mca_proc_state_dump;; + mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack + LOAD_PHYSICAL(p0,r2,1f) // return address + mov r19=1 // All MCA events are treated as monarch (for now) + br.sptk ia64_state_save // save the state that is not in minstate +1: -ia64_os_mca_done_dump: - - LOAD_PHYSICAL(p0,r16,ia64_sal_to_os_handoff_state+56) + GET_IA64_MCA_DATA(r2) + // Using MCA stack, struct ia64_sal_os_state, variable proc_state_param + ;; + add r3=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SOS_OFFSET+IA64_SAL_OS_STATE_PROC_STATE_PARAM_OFFSET, r2 ;; - ld8 r18=[r16] // Get processor state parameter on existing PALE_CHECK. + ld8 r18=[r3] // Get processor state parameter on existing PALE_CHECK. ;; tbit.nz p6,p7=r18,60 (p7) br.spnt done_tlb_purge_and_reload @@ -323,624 +250,775 @@ ia64_reload_tr: itr.d dtr[r20]=r16 ;; srlz.d - ;; - br.sptk.many done_tlb_purge_and_reload -err: - COLD_BOOT_HANDOFF_STATE(r20,r21,r22) - br.sptk.many ia64_os_mca_done_restore done_tlb_purge_and_reload: - // Setup new stack frame for OS_MCA handling - GET_IA64_MCA_DATA(r2) - ;; - add r3 = IA64_MCA_CPU_STACKFRAME_OFFSET, r2 - add r2 = IA64_MCA_CPU_RBSTORE_OFFSET, r2 - ;; - rse_switch_context(r6,r3,r2);; // RSC management in this new context + // switch to per cpu MCA stack + mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack + LOAD_PHYSICAL(p0,r2,1f) // return address + br.sptk ia64_new_stack +1: + + // everything saved, now we can set the kernel registers + mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack + LOAD_PHYSICAL(p0,r2,1f) // return address + br.sptk ia64_set_kernel_registers +1: + // This must be done in physical mode GET_IA64_MCA_DATA(r2) ;; - add r2 = IA64_MCA_CPU_STACK_OFFSET+IA64_MCA_STACK_SIZE-16, r2 - ;; - mov r12=r2 // establish new stack-pointer + mov r7=r2 // Enter virtual mode from physical mode VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4) -ia64_os_mca_virtual_begin: + + // This code returns to SAL via SOS r2, in general SAL has no unwind + // data. To get a clean termination when backtracing the C MCA/INIT + // handler, set a dummy return address of 0 in this routine. That + // requires that ia64_os_mca_virtual_begin be a global function. +ENTRY(ia64_os_mca_virtual_begin) + .prologue + .save rp,r0 + .body + + mov ar.rsc=3 // set eager mode for C handler + mov r2=r7 // see GET_IA64_MCA_DATA above + ;; // Call virtual mode handler - movl r2=ia64_mca_ucmc_handler;; - mov b6=r2;; - br.call.sptk.many b0=b6;; -.ret0: + alloc r14=ar.pfs,0,0,3,0 + ;; + DATA_PA_TO_VA(r2,r7) + ;; + add out0=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_PT_REGS_OFFSET, r2 + add out1=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SWITCH_STACK_OFFSET, r2 + add out2=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SOS_OFFSET, r2 + br.call.sptk.many b0=ia64_mca_handler + // Revert back to physical mode before going back to SAL PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4) ia64_os_mca_virtual_end: - // restore the original stack frame here +END(ia64_os_mca_virtual_begin) + + // switch back to previous stack + alloc r14=ar.pfs,0,0,0,0 // remove the MCA handler frame + mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack + LOAD_PHYSICAL(p0,r2,1f) // return address + br.sptk ia64_old_stack +1: + + mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack + LOAD_PHYSICAL(p0,r2,1f) // return address + br.sptk ia64_state_restore // restore the SAL state +1: + + mov b0=r12 // SAL_CHECK return address + + // release lock + LOAD_PHYSICAL(p0,r3,ia64_mca_serialize);; + st4.rel [r3]=r0 + + br b0 + +//EndMain////////////////////////////////////////////////////////////////////// + +//StartMain//////////////////////////////////////////////////////////////////// + +// +// SAL to OS entry point for INIT on all processors. This has been defined for +// registration purposes with SAL as a part of ia64_mca_init. Monarch and +// slave INIT have identical processing, except for the value of the +// sos->monarch flag in r19. +// + +ia64_os_init_dispatch_monarch: + mov r19=1 // Bow, bow, ye lower middle classes! + br.sptk ia64_os_init_dispatch + +ia64_os_init_dispatch_slave: + mov r19=0 // <igor>yeth, mathter</igor> + +ia64_os_init_dispatch: + + mov r3=IA64_MCA_CPU_INIT_STACK_OFFSET // use the INIT stack + LOAD_PHYSICAL(p0,r2,1f) // return address + br.sptk ia64_state_save // save the state that is not in minstate +1: + + // switch to per cpu INIT stack + mov r3=IA64_MCA_CPU_INIT_STACK_OFFSET // use the INIT stack + LOAD_PHYSICAL(p0,r2,1f) // return address + br.sptk ia64_new_stack +1: + + // everything saved, now we can set the kernel registers + mov r3=IA64_MCA_CPU_INIT_STACK_OFFSET // use the INIT stack + LOAD_PHYSICAL(p0,r2,1f) // return address + br.sptk ia64_set_kernel_registers +1: + + // This must be done in physical mode GET_IA64_MCA_DATA(r2) ;; - add r2 = IA64_MCA_CPU_STACKFRAME_OFFSET, r2 - ;; - movl r4=IA64_PSR_MC + mov r7=r2 + + // Enter virtual mode from physical mode + VIRTUAL_MODE_ENTER(r2, r3, ia64_os_init_virtual_begin, r4) + + // This code returns to SAL via SOS r2, in general SAL has no unwind + // data. To get a clean termination when backtracing the C MCA/INIT + // handler, set a dummy return address of 0 in this routine. That + // requires that ia64_os_init_virtual_begin be a global function. +ENTRY(ia64_os_init_virtual_begin) + .prologue + .save rp,r0 + .body + + mov ar.rsc=3 // set eager mode for C handler + mov r2=r7 // see GET_IA64_MCA_DATA above ;; - rse_return_context(r4,r3,r2) // switch from interrupt context for RSE - // let us restore all the registers from our PSI structure - mov r8=gp + // Call virtual mode handler + alloc r14=ar.pfs,0,0,3,0 + ;; + DATA_PA_TO_VA(r2,r7) ;; -begin_os_mca_restore: - br ia64_os_mca_proc_state_restore;; + add out0=IA64_MCA_CPU_INIT_STACK_OFFSET+MCA_PT_REGS_OFFSET, r2 + add out1=IA64_MCA_CPU_INIT_STACK_OFFSET+MCA_SWITCH_STACK_OFFSET, r2 + add out2=IA64_MCA_CPU_INIT_STACK_OFFSET+MCA_SOS_OFFSET, r2 + br.call.sptk.many b0=ia64_init_handler -ia64_os_mca_done_restore: - OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2);; - // branch back to SALE_CHECK - ld8 r3=[r2];; - mov b0=r3;; // SAL_CHECK return address + // Revert back to physical mode before going back to SAL + PHYSICAL_MODE_ENTER(r2, r3, ia64_os_init_virtual_end, r4) +ia64_os_init_virtual_end: - // release lock - movl r3=ia64_mca_serialize;; - DATA_VA_TO_PA(r3);; - st8.rel [r3]=r0 +END(ia64_os_init_virtual_begin) + + mov r3=IA64_MCA_CPU_INIT_STACK_OFFSET // use the INIT stack + LOAD_PHYSICAL(p0,r2,1f) // return address + br.sptk ia64_state_restore // restore the SAL state +1: + // switch back to previous stack + alloc r14=ar.pfs,0,0,0,0 // remove the INIT handler frame + mov r3=IA64_MCA_CPU_INIT_STACK_OFFSET // use the INIT stack + LOAD_PHYSICAL(p0,r2,1f) // return address + br.sptk ia64_old_stack +1: + + mov b0=r12 // SAL_CHECK return address br b0 - ;; -ia64_os_mca_dispatch_end: + //EndMain////////////////////////////////////////////////////////////////////// +// common defines for the stubs +#define ms r4 +#define regs r5 +#define temp1 r2 /* careful, it overlaps with input registers */ +#define temp2 r3 /* careful, it overlaps with input registers */ +#define temp3 r7 +#define temp4 r14 + //++ // Name: -// ia64_os_mca_proc_state_dump() +// ia64_state_save() // // Stub Description: // -// This stub dumps the processor state during MCHK to a data area +// Save the state that is not in minstate. This is sensitive to the layout of +// struct ia64_sal_os_state in mca.h. +// +// r2 contains the return address, r3 contains either +// IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET. +// +// The OS to SAL section of struct ia64_sal_os_state is set to a default +// value of cold boot (MCA) or warm boot (INIT) and return to the same +// context. ia64_sal_os_state is also used to hold some registers that +// need to be saved and restored across the stack switches. +// +// Most input registers to this stub come from PAL/SAL +// r1 os gp, physical +// r8 pal_proc entry point +// r9 sal_proc entry point +// r10 sal gp +// r11 MCA - rendevzous state, INIT - reason code +// r12 sal return address +// r17 pal min_state +// r18 processor state parameter +// r19 monarch flag, set by the caller of this routine +// +// In addition to the SAL to OS state, this routine saves all the +// registers that appear in struct pt_regs and struct switch_stack, +// excluding those that are already in the PAL minstate area. This +// results in a partial pt_regs and switch_stack, the C code copies the +// remaining registers from PAL minstate to pt_regs and switch_stack. The +// resulting structures contain all the state of the original process when +// MCA/INIT occurred. // //-- -ia64_os_mca_proc_state_dump: -// Save bank 1 GRs 16-31 which will be used by c-language code when we switch -// to virtual addressing mode. - GET_IA64_MCA_DATA(r2) +ia64_state_save: + add regs=MCA_SOS_OFFSET, r3 + add ms=MCA_SOS_OFFSET+8, r3 + mov b0=r2 // save return address + cmp.eq p1,p2=IA64_MCA_CPU_MCA_STACK_OFFSET, r3 + ;; + GET_IA64_MCA_DATA(temp2) + ;; + add temp1=temp2, regs // struct ia64_sal_os_state on MCA or INIT stack + add temp2=temp2, ms // struct ia64_sal_os_state+8 on MCA or INIT stack + ;; + mov regs=temp1 // save the start of sos + st8 [temp1]=r1,16 // os_gp + st8 [temp2]=r8,16 // pal_proc + ;; + st8 [temp1]=r9,16 // sal_proc + st8 [temp2]=r11,16 // rv_rc + mov r11=cr.iipa + ;; + st8 [temp1]=r18,16 // proc_state_param + st8 [temp2]=r19,16 // monarch + mov r6=IA64_KR(CURRENT) + ;; + st8 [temp1]=r12,16 // sal_ra + st8 [temp2]=r10,16 // sal_gp + mov r12=cr.isr + ;; + st8 [temp1]=r17,16 // pal_min_state + st8 [temp2]=r6,16 // prev_IA64_KR_CURRENT + mov r6=cr.ifa + ;; + st8 [temp1]=r0,16 // prev_task, starts off as NULL + st8 [temp2]=r12,16 // cr.isr + mov r12=cr.itir + ;; + st8 [temp1]=r6,16 // cr.ifa + st8 [temp2]=r12,16 // cr.itir + mov r12=cr.iim + ;; + st8 [temp1]=r11,16 // cr.iipa + st8 [temp2]=r12,16 // cr.iim + mov r6=cr.iha +(p1) mov r12=IA64_MCA_COLD_BOOT +(p2) mov r12=IA64_INIT_WARM_BOOT + ;; + st8 [temp1]=r6,16 // cr.iha + st8 [temp2]=r12 // os_status, default is cold boot + mov r6=IA64_MCA_SAME_CONTEXT + ;; + st8 [temp1]=r6 // context, default is same context + + // Save the pt_regs data that is not in minstate. The previous code + // left regs at sos. + add regs=MCA_PT_REGS_OFFSET-MCA_SOS_OFFSET, regs + ;; + add temp1=PT(B6), regs + mov temp3=b6 + mov temp4=b7 + add temp2=PT(B7), regs + ;; + st8 [temp1]=temp3,PT(AR_CSD)-PT(B6) // save b6 + st8 [temp2]=temp4,PT(AR_SSD)-PT(B7) // save b7 + mov temp3=ar.csd + mov temp4=ar.ssd + cover // must be last in group ;; - add r2 = IA64_MCA_CPU_PROC_STATE_DUMP_OFFSET, r2 - ;; -// save ar.NaT - mov r5=ar.unat // ar.unat - -// save banked GRs 16-31 along with NaT bits - bsw.1;; - st8.spill [r2]=r16,8;; - st8.spill [r2]=r17,8;; - st8.spill [r2]=r18,8;; - st8.spill [r2]=r19,8;; - st8.spill [r2]=r20,8;; - st8.spill [r2]=r21,8;; - st8.spill [r2]=r22,8;; - st8.spill [r2]=r23,8;; - st8.spill [r2]=r24,8;; - st8.spill [r2]=r25,8;; - st8.spill [r2]=r26,8;; - st8.spill [r2]=r27,8;; - st8.spill [r2]=r28,8;; - st8.spill [r2]=r29,8;; - st8.spill [r2]=r30,8;; - st8.spill [r2]=r31,8;; - - mov r4=ar.unat;; - st8 [r2]=r4,8 // save User NaT bits for r16-r31 - mov ar.unat=r5 // restore original unat - bsw.0;; - -//save BRs - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r4 - - mov r3=b0 - mov r5=b1 - mov r7=b2;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=b3 - mov r5=b4 - mov r7=b5;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=b6 - mov r5=b7;; - st8 [r2]=r3,2*8 - st8 [r4]=r5,2*8;; - -cSaveCRs: -// save CRs - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r4 - - mov r3=cr.dcr - mov r5=cr.itm - mov r7=cr.iva;; - - st8 [r2]=r3,8*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; // 48 byte rements - - mov r3=cr.pta;; - st8 [r2]=r3,8*8;; // 64 byte rements - -// if PSR.ic=0, reading interruption registers causes an illegal operation fault - mov r3=psr;; - tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test -(p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc. -begin_skip_intr_regs: -(p6) br SkipIntrRegs;; - - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r6 - - mov r3=cr.ipsr - mov r5=cr.isr - mov r7=r0;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=cr.iip - mov r5=cr.ifa - mov r7=cr.itir;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=cr.iipa - mov r5=cr.ifs - mov r7=cr.iim;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=cr25;; // cr.iha - st8 [r2]=r3,160;; // 160 byte rement - -SkipIntrRegs: - st8 [r2]=r0,152;; // another 152 byte . - - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r6 - - mov r3=cr.lid -// mov r5=cr.ivr // cr.ivr, don't read it - mov r7=cr.tpr;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=r0 // cr.eoi => cr67 - mov r5=r0 // cr.irr0 => cr68 - mov r7=r0;; // cr.irr1 => cr69 - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=r0 // cr.irr2 => cr70 - mov r5=r0 // cr.irr3 => cr71 - mov r7=cr.itv;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=cr.pmv - mov r5=cr.cmcv;; - st8 [r2]=r3,7*8 - st8 [r4]=r5,7*8;; - - mov r3=r0 // cr.lrr0 => cr80 - mov r5=r0;; // cr.lrr1 => cr81 - st8 [r2]=r3,23*8 - st8 [r4]=r5,23*8;; - - adds r2=25*8,r2;; - -cSaveARs: -// save ARs - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2 // duplicate r2 in r6 - - mov r3=ar.k0 - mov r5=ar.k1 - mov r7=ar.k2;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=ar.k3 - mov r5=ar.k4 - mov r7=ar.k5;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=ar.k6 - mov r5=ar.k7 - mov r7=r0;; // ar.kr8 - st8 [r2]=r3,10*8 - st8 [r4]=r5,10*8 - st8 [r6]=r7,10*8;; // rement by 72 bytes - - mov r3=ar.rsc - mov ar.rsc=r0 // put RSE in enforced lazy mode - mov r5=ar.bsp - ;; - mov r7=ar.bspstore;; - st8 [r2]=r3,3*8 - st8 [r4]=r5,3*8 - st8 [r6]=r7,3*8;; - - mov r3=ar.rnat;; - st8 [r2]=r3,8*13 // increment by 13x8 bytes - - mov r3=ar.ccv;; - st8 [r2]=r3,8*4 - - mov r3=ar.unat;; - st8 [r2]=r3,8*4 - - mov r3=ar.fpsr;; - st8 [r2]=r3,8*4 - - mov r3=ar.itc;; - st8 [r2]=r3,160 // 160 - - mov r3=ar.pfs;; - st8 [r2]=r3,8 - - mov r3=ar.lc;; - st8 [r2]=r3,8 - - mov r3=ar.ec;; - st8 [r2]=r3 - add r2=8*62,r2 //padding - -// save RRs - mov ar.lc=0x08-1 - movl r4=0x00;; - -cStRR: - dep.z r5=r4,61,3;; - mov r3=rr[r5];; - st8 [r2]=r3,8 - add r4=1,r4 - br.cloop.sptk.few cStRR - ;; -end_os_mca_dump: - br ia64_os_mca_done_dump;; + st8 [temp1]=temp3,PT(AR_UNAT)-PT(AR_CSD) // save ar.csd + st8 [temp2]=temp4,PT(AR_PFS)-PT(AR_SSD) // save ar.ssd + mov temp3=ar.unat + mov temp4=ar.pfs + ;; + st8 [temp1]=temp3,PT(AR_RNAT)-PT(AR_UNAT) // save ar.unat + st8 [temp2]=temp4,PT(AR_BSPSTORE)-PT(AR_PFS) // save ar.pfs + mov temp3=ar.rnat + mov temp4=ar.bspstore + ;; + st8 [temp1]=temp3,PT(LOADRS)-PT(AR_RNAT) // save ar.rnat + st8 [temp2]=temp4,PT(AR_FPSR)-PT(AR_BSPSTORE) // save ar.bspstore + mov temp3=ar.bsp + ;; + sub temp3=temp3, temp4 // ar.bsp - ar.bspstore + mov temp4=ar.fpsr + ;; + shl temp3=temp3,16 // compute ar.rsc to be used for "loadrs" + ;; + st8 [temp1]=temp3,PT(AR_CCV)-PT(LOADRS) // save loadrs + st8 [temp2]=temp4,PT(F6)-PT(AR_FPSR) // save ar.fpsr + mov temp3=ar.ccv + ;; + st8 [temp1]=temp3,PT(F7)-PT(AR_CCV) // save ar.ccv + stf.spill [temp2]=f6,PT(F8)-PT(F6) + ;; + stf.spill [temp1]=f7,PT(F9)-PT(F7) + stf.spill [temp2]=f8,PT(F10)-PT(F8) + ;; + stf.spill [temp1]=f9,PT(F11)-PT(F9) + stf.spill [temp2]=f10 + ;; + stf.spill [temp1]=f11 + + // Save the switch_stack data that is not in minstate nor pt_regs. The + // previous code left regs at pt_regs. + add regs=MCA_SWITCH_STACK_OFFSET-MCA_PT_REGS_OFFSET, regs + ;; + add temp1=SW(F2), regs + add temp2=SW(F3), regs + ;; + stf.spill [temp1]=f2,32 + stf.spill [temp2]=f3,32 + ;; + stf.spill [temp1]=f4,32 + stf.spill [temp2]=f5,32 + ;; + stf.spill [temp1]=f12,32 + stf.spill [temp2]=f13,32 + ;; + stf.spill [temp1]=f14,32 + stf.spill [temp2]=f15,32 + ;; + stf.spill [temp1]=f16,32 + stf.spill [temp2]=f17,32 + ;; + stf.spill [temp1]=f18,32 + stf.spill [temp2]=f19,32 + ;; + stf.spill [temp1]=f20,32 + stf.spill [temp2]=f21,32 + ;; + stf.spill [temp1]=f22,32 + stf.spill [temp2]=f23,32 + ;; + stf.spill [temp1]=f24,32 + stf.spill [temp2]=f25,32 + ;; + stf.spill [temp1]=f26,32 + stf.spill [temp2]=f27,32 + ;; + stf.spill [temp1]=f28,32 + stf.spill [temp2]=f29,32 + ;; + stf.spill [temp1]=f30,SW(B2)-SW(F30) + stf.spill [temp2]=f31,SW(B3)-SW(F31) + mov temp3=b2 + mov temp4=b3 + ;; + st8 [temp1]=temp3,16 // save b2 + st8 [temp2]=temp4,16 // save b3 + mov temp3=b4 + mov temp4=b5 + ;; + st8 [temp1]=temp3,SW(AR_LC)-SW(B4) // save b4 + st8 [temp2]=temp4 // save b5 + mov temp3=ar.lc + ;; + st8 [temp1]=temp3 // save ar.lc + + // FIXME: Some proms are incorrectly accessing the minstate area as + // cached data. The C code uses region 6, uncached virtual. Ensure + // that there is no cache data lying around for the first 1K of the + // minstate area. + // Remove this code in September 2006, that gives platforms a year to + // fix their proms and get their customers updated. + + add r1=32*1,r17 + add r2=32*2,r17 + add r3=32*3,r17 + add r4=32*4,r17 + add r5=32*5,r17 + add r6=32*6,r17 + add r7=32*7,r17 + ;; + fc r17 + fc r1 + fc r2 + fc r3 + fc r4 + fc r5 + fc r6 + fc r7 + add r17=32*8,r17 + add r1=32*8,r1 + add r2=32*8,r2 + add r3=32*8,r3 + add r4=32*8,r4 + add r5=32*8,r5 + add r6=32*8,r6 + add r7=32*8,r7 + ;; + fc r17 + fc r1 + fc r2 + fc r3 + fc r4 + fc r5 + fc r6 + fc r7 + add r17=32*8,r17 + add r1=32*8,r1 + add r2=32*8,r2 + add r3=32*8,r3 + add r4=32*8,r4 + add r5=32*8,r5 + add r6=32*8,r6 + add r7=32*8,r7 + ;; + fc r17 + fc r1 + fc r2 + fc r3 + fc r4 + fc r5 + fc r6 + fc r7 + add r17=32*8,r17 + add r1=32*8,r1 + add r2=32*8,r2 + add r3=32*8,r3 + add r4=32*8,r4 + add r5=32*8,r5 + add r6=32*8,r6 + add r7=32*8,r7 + ;; + fc r17 + fc r1 + fc r2 + fc r3 + fc r4 + fc r5 + fc r6 + fc r7 + + br.sptk b0 //EndStub////////////////////////////////////////////////////////////////////// //++ // Name: -// ia64_os_mca_proc_state_restore() +// ia64_state_restore() // // Stub Description: // -// This is a stub to restore the saved processor state during MCHK +// Restore the SAL/OS state. This is sensitive to the layout of struct +// ia64_sal_os_state in mca.h. +// +// r2 contains the return address, r3 contains either +// IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET. +// +// In addition to the SAL to OS state, this routine restores all the +// registers that appear in struct pt_regs and struct switch_stack, +// excluding those in the PAL minstate area. // //-- -ia64_os_mca_proc_state_restore: +ia64_state_restore: + // Restore the switch_stack data that is not in minstate nor pt_regs. + add regs=MCA_SWITCH_STACK_OFFSET, r3 + mov b0=r2 // save return address + ;; + GET_IA64_MCA_DATA(temp2) + ;; + add regs=temp2, regs + ;; + add temp1=SW(F2), regs + add temp2=SW(F3), regs + ;; + ldf.fill f2=[temp1],32 + ldf.fill f3=[temp2],32 + ;; + ldf.fill f4=[temp1],32 + ldf.fill f5=[temp2],32 + ;; + ldf.fill f12=[temp1],32 + ldf.fill f13=[temp2],32 + ;; + ldf.fill f14=[temp1],32 + ldf.fill f15=[temp2],32 + ;; + ldf.fill f16=[temp1],32 + ldf.fill f17=[temp2],32 + ;; + ldf.fill f18=[temp1],32 + ldf.fill f19=[temp2],32 + ;; + ldf.fill f20=[temp1],32 + ldf.fill f21=[temp2],32 + ;; + ldf.fill f22=[temp1],32 + ldf.fill f23=[temp2],32 + ;; + ldf.fill f24=[temp1],32 + ldf.fill f25=[temp2],32 + ;; + ldf.fill f26=[temp1],32 + ldf.fill f27=[temp2],32 + ;; + ldf.fill f28=[temp1],32 + ldf.fill f29=[temp2],32 + ;; + ldf.fill f30=[temp1],SW(B2)-SW(F30) + ldf.fill f31=[temp2],SW(B3)-SW(F31) + ;; + ld8 temp3=[temp1],16 // restore b2 + ld8 temp4=[temp2],16 // restore b3 + ;; + mov b2=temp3 + mov b3=temp4 + ld8 temp3=[temp1],SW(AR_LC)-SW(B4) // restore b4 + ld8 temp4=[temp2] // restore b5 + ;; + mov b4=temp3 + mov b5=temp4 + ld8 temp3=[temp1] // restore ar.lc + ;; + mov ar.lc=temp3 -// Restore bank1 GR16-31 - GET_IA64_MCA_DATA(r2) + // Restore the pt_regs data that is not in minstate. The previous code + // left regs at switch_stack. + add regs=MCA_PT_REGS_OFFSET-MCA_SWITCH_STACK_OFFSET, regs + ;; + add temp1=PT(B6), regs + add temp2=PT(B7), regs + ;; + ld8 temp3=[temp1],PT(AR_CSD)-PT(B6) // restore b6 + ld8 temp4=[temp2],PT(AR_SSD)-PT(B7) // restore b7 + ;; + mov b6=temp3 + mov b7=temp4 + ld8 temp3=[temp1],PT(AR_UNAT)-PT(AR_CSD) // restore ar.csd + ld8 temp4=[temp2],PT(AR_PFS)-PT(AR_SSD) // restore ar.ssd + ;; + mov ar.csd=temp3 + mov ar.ssd=temp4 + ld8 temp3=[temp1] // restore ar.unat + add temp1=PT(AR_CCV)-PT(AR_UNAT), temp1 + ld8 temp4=[temp2],PT(AR_FPSR)-PT(AR_PFS) // restore ar.pfs + ;; + mov ar.unat=temp3 + mov ar.pfs=temp4 + // ar.rnat, ar.bspstore, loadrs are restore in ia64_old_stack. + ld8 temp3=[temp1],PT(F6)-PT(AR_CCV) // restore ar.ccv + ld8 temp4=[temp2],PT(F7)-PT(AR_FPSR) // restore ar.fpsr + ;; + mov ar.ccv=temp3 + mov ar.fpsr=temp4 + ldf.fill f6=[temp1],PT(F8)-PT(F6) + ldf.fill f7=[temp2],PT(F9)-PT(F7) + ;; + ldf.fill f8=[temp1],PT(F10)-PT(F8) + ldf.fill f9=[temp2],PT(F11)-PT(F9) + ;; + ldf.fill f10=[temp1] + ldf.fill f11=[temp2] + + // Restore the SAL to OS state. The previous code left regs at pt_regs. + add regs=MCA_SOS_OFFSET-MCA_PT_REGS_OFFSET, regs ;; - add r2 = IA64_MCA_CPU_PROC_STATE_DUMP_OFFSET, r2 - -restore_GRs: // restore bank-1 GRs 16-31 - bsw.1;; - add r3=16*8,r2;; // to get to NaT of GR 16-31 - ld8 r3=[r3];; - mov ar.unat=r3;; // first restore NaT - - ld8.fill r16=[r2],8;; - ld8.fill r17=[r2],8;; - ld8.fill r18=[r2],8;; - ld8.fill r19=[r2],8;; - ld8.fill r20=[r2],8;; - ld8.fill r21=[r2],8;; - ld8.fill r22=[r2],8;; - ld8.fill r23=[r2],8;; - ld8.fill r24=[r2],8;; - ld8.fill r25=[r2],8;; - ld8.fill r26=[r2],8;; - ld8.fill r27=[r2],8;; - ld8.fill r28=[r2],8;; - ld8.fill r29=[r2],8;; - ld8.fill r30=[r2],8;; - ld8.fill r31=[r2],8;; - - ld8 r3=[r2],8;; // increment to skip NaT - bsw.0;; - -restore_BRs: - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov b0=r3 - mov b1=r5 - mov b2=r7;; - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov b3=r3 - mov b4=r5 - mov b5=r7;; - - ld8 r3=[r2],2*8 - ld8 r5=[r4],2*8;; - mov b6=r3 - mov b7=r5;; - -restore_CRs: - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 - - ld8 r3=[r2],8*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; // 48 byte increments - mov cr.dcr=r3 - mov cr.itm=r5 - mov cr.iva=r7;; - - ld8 r3=[r2],8*8;; // 64 byte increments -// mov cr.pta=r3 - - -// if PSR.ic=1, reading interruption registers causes an illegal operation fault - mov r3=psr;; - tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test -(p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc. - -begin_rskip_intr_regs: -(p6) br rSkipIntrRegs;; - - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov cr.ipsr=r3 -// mov cr.isr=r5 // cr.isr is read only - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov cr.iip=r3 - mov cr.ifa=r5 - mov cr.itir=r7;; - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov cr.iipa=r3 - mov cr.ifs=r5 - mov cr.iim=r7 - - ld8 r3=[r2],160;; // 160 byte increment - mov cr.iha=r3 - -rSkipIntrRegs: - ld8 r3=[r2],152;; // another 152 byte inc. - - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r6 - - ld8 r3=[r2],8*3 - ld8 r5=[r4],8*3 - ld8 r7=[r6],8*3;; - mov cr.lid=r3 -// mov cr.ivr=r5 // cr.ivr is read only - mov cr.tpr=r7;; - - ld8 r3=[r2],8*3 - ld8 r5=[r4],8*3 - ld8 r7=[r6],8*3;; -// mov cr.eoi=r3 -// mov cr.irr0=r5 // cr.irr0 is read only -// mov cr.irr1=r7;; // cr.irr1 is read only - - ld8 r3=[r2],8*3 - ld8 r5=[r4],8*3 - ld8 r7=[r6],8*3;; -// mov cr.irr2=r3 // cr.irr2 is read only -// mov cr.irr3=r5 // cr.irr3 is read only - mov cr.itv=r7;; - - ld8 r3=[r2],8*7 - ld8 r5=[r4],8*7;; - mov cr.pmv=r3 - mov cr.cmcv=r5;; - - ld8 r3=[r2],8*23 - ld8 r5=[r4],8*23;; - adds r2=8*23,r2 - adds r4=8*23,r4;; -// mov cr.lrr0=r3 -// mov cr.lrr1=r5 - - adds r2=8*2,r2;; - -restore_ARs: - add r4=8,r2 // duplicate r2 in r4 - add r6=2*8,r2;; // duplicate r2 in r4 - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov ar.k0=r3 - mov ar.k1=r5 - mov ar.k2=r7;; - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; - mov ar.k3=r3 - mov ar.k4=r5 - mov ar.k5=r7;; - - ld8 r3=[r2],10*8 - ld8 r5=[r4],10*8 - ld8 r7=[r6],10*8;; - mov ar.k6=r3 - mov ar.k7=r5 - ;; - - ld8 r3=[r2],3*8 - ld8 r5=[r4],3*8 - ld8 r7=[r6],3*8;; -// mov ar.rsc=r3 -// mov ar.bsp=r5 // ar.bsp is read only - mov ar.rsc=r0 // make sure that RSE is in enforced lazy mode - ;; - mov ar.bspstore=r7;; - - ld8 r9=[r2],8*13;; - mov ar.rnat=r9 - - mov ar.rsc=r3 - ld8 r3=[r2],8*4;; - mov ar.ccv=r3 - - ld8 r3=[r2],8*4;; - mov ar.unat=r3 - - ld8 r3=[r2],8*4;; - mov ar.fpsr=r3 - - ld8 r3=[r2],160;; // 160 -// mov ar.itc=r3 - - ld8 r3=[r2],8;; - mov ar.pfs=r3 - - ld8 r3=[r2],8;; - mov ar.lc=r3 - - ld8 r3=[r2];; - mov ar.ec=r3 - add r2=8*62,r2;; // padding - -restore_RRs: - mov r5=ar.lc - mov ar.lc=0x08-1 - movl r4=0x00;; -cStRRr: - dep.z r7=r4,61,3 - ld8 r3=[r2],8;; - mov rr[r7]=r3 // what are its access previledges? - add r4=1,r4 - br.cloop.sptk.few cStRRr - ;; - mov ar.lc=r5 - ;; -end_os_mca_restore: - br ia64_os_mca_done_restore;; + add temp1=IA64_SAL_OS_STATE_COMMON_OFFSET, regs + add temp2=IA64_SAL_OS_STATE_COMMON_OFFSET+8, regs + ;; + ld8 r12=[temp1],16 // sal_ra + ld8 r9=[temp2],16 // sal_gp + ;; + ld8 r22=[temp1],24 // pal_min_state, virtual. skip prev_task + ld8 r21=[temp2],16 // prev_IA64_KR_CURRENT + ;; + ld8 temp3=[temp1],16 // cr.isr + ld8 temp4=[temp2],16 // cr.ifa + ;; + mov cr.isr=temp3 + mov cr.ifa=temp4 + ld8 temp3=[temp1],16 // cr.itir + ld8 temp4=[temp2],16 // cr.iipa + ;; + mov cr.itir=temp3 + mov cr.iipa=temp4 + ld8 temp3=[temp1],16 // cr.iim + ld8 temp4=[temp2],16 // cr.iha + ;; + mov cr.iim=temp3 + mov cr.iha=temp4 + dep r22=0,r22,62,2 // pal_min_state, physical, uncached + mov IA64_KR(CURRENT)=r21 + ld8 r8=[temp1] // os_status + ld8 r10=[temp2] // context + + br.sptk b0 //EndStub////////////////////////////////////////////////////////////////////// -// ok, the issue here is that we need to save state information so -// it can be useable by the kernel debugger and show regs routines. -// In order to do this, our best bet is save the current state (plus -// the state information obtain from the MIN_STATE_AREA) into a pt_regs -// format. This way we can pass it on in a useable format. +//++ +// Name: +// ia64_new_stack() // - +// Stub Description: // -// SAL to OS entry point for INIT on the monarch processor -// This has been defined for registration purposes with SAL -// as a part of ia64_mca_init. +// Switch to the MCA/INIT stack. // -// When we get here, the following registers have been -// set by the SAL for our use +// r2 contains the return address, r3 contains either +// IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET. // -// 1. GR1 = OS INIT GP -// 2. GR8 = PAL_PROC physical address -// 3. GR9 = SAL_PROC physical address -// 4. GR10 = SAL GP (physical) -// 5. GR11 = Init Reason -// 0 = Received INIT for event other than crash dump switch -// 1 = Received wakeup at the end of an OS_MCA corrected machine check -// 2 = Received INIT dude to CrashDump switch assertion +// On entry RBS is still on the original stack, this routine switches RBS +// to use the MCA/INIT stack. // -// 6. GR12 = Return address to location within SAL_INIT procedure - +// On entry, sos->pal_min_state is physical, on exit it is virtual. +// +//-- -GLOBAL_ENTRY(ia64_monarch_init_handler) - .prologue - // stash the information the SAL passed to os - SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2) +ia64_new_stack: + add regs=MCA_PT_REGS_OFFSET, r3 + add temp2=MCA_SOS_OFFSET+IA64_SAL_OS_STATE_PAL_MIN_STATE_OFFSET, r3 + mov b0=r2 // save return address + GET_IA64_MCA_DATA(temp1) + invala ;; - SAVE_MIN_WITH_COVER + add temp2=temp2, temp1 // struct ia64_sal_os_state.pal_min_state on MCA or INIT stack + add regs=regs, temp1 // struct pt_regs on MCA or INIT stack ;; - mov r8=cr.ifa - mov r9=cr.isr - adds r3=8,r2 // set up second base pointer + // Address of minstate area provided by PAL is physical, uncacheable. + // Convert to Linux virtual address in region 6 for C code. + ld8 ms=[temp2] // pal_min_state, physical ;; - SAVE_REST - -// ok, enough should be saved at this point to be dangerous, and supply -// information for a dump -// We need to switch to Virtual mode before hitting the C functions. + dep temp1=-1,ms,62,2 // set region 6 + mov temp3=IA64_RBS_OFFSET-MCA_PT_REGS_OFFSET + ;; + st8 [temp2]=temp1 // pal_min_state, virtual - movl r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN - mov r3=psr // get the current psr, minimum enabled at this point + add temp4=temp3, regs // start of bspstore on new stack ;; - or r2=r2,r3 + mov ar.bspstore=temp4 // switch RBS to MCA/INIT stack ;; - movl r3=IVirtual_Switch + flushrs // must be first in group + br.sptk b0 + +//EndStub////////////////////////////////////////////////////////////////////// + + +//++ +// Name: +// ia64_old_stack() +// +// Stub Description: +// +// Switch to the old stack. +// +// r2 contains the return address, r3 contains either +// IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET. +// +// On entry, pal_min_state is virtual, on exit it is physical. +// +// On entry RBS is on the MCA/INIT stack, this routine switches RBS +// back to the previous stack. +// +// The psr is set to all zeroes. SAL return requires either all zeroes or +// just psr.mc set. Leaving psr.mc off allows INIT to be issued if this +// code does not perform correctly. +// +// The dirty registers at the time of the event were flushed to the +// MCA/INIT stack in ia64_pt_regs_save(). Restore the dirty registers +// before reverting to the previous bspstore. +//-- + +ia64_old_stack: + add regs=MCA_PT_REGS_OFFSET, r3 + mov b0=r2 // save return address + GET_IA64_MCA_DATA(temp2) + LOAD_PHYSICAL(p0,temp1,1f) ;; - mov cr.iip=r3 // short return to set the appropriate bits - mov cr.ipsr=r2 // need to do an rfi to set appropriate bits + mov cr.ipsr=r0 + mov cr.ifs=r0 + mov cr.iip=temp1 ;; + invala rfi +1: + + add regs=regs, temp2 // struct pt_regs on MCA or INIT stack ;; -IVirtual_Switch: - // - // We should now be running virtual - // - // Let's call the C handler to get the rest of the state info - // - alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!) + add temp1=PT(LOADRS), regs ;; - adds out0=16,sp // out0 = pointer to pt_regs + ld8 temp2=[temp1],PT(AR_BSPSTORE)-PT(LOADRS) // restore loadrs ;; - DO_SAVE_SWITCH_STACK - .body - adds out1=16,sp // out0 = pointer to switch_stack + ld8 temp3=[temp1],PT(AR_RNAT)-PT(AR_BSPSTORE) // restore ar.bspstore + mov ar.rsc=temp2 + ;; + loadrs + ld8 temp4=[temp1] // restore ar.rnat + ;; + mov ar.bspstore=temp3 // back to old stack + ;; + mov ar.rnat=temp4 + ;; + + br.sptk b0 - br.call.sptk.many rp=ia64_init_handler -.ret1: +//EndStub////////////////////////////////////////////////////////////////////// -return_from_init: - br.sptk return_from_init -END(ia64_monarch_init_handler) +//++ +// Name: +// ia64_set_kernel_registers() // -// SAL to OS entry point for INIT on the slave processor -// This has been defined for registration purposes with SAL -// as a part of ia64_mca_init. +// Stub Description: +// +// Set the registers that are required by the C code in order to run on an +// MCA/INIT stack. +// +// r2 contains the return address, r3 contains either +// IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET. // +//-- + +ia64_set_kernel_registers: + add temp3=MCA_SP_OFFSET, r3 + add temp4=MCA_SOS_OFFSET+IA64_SAL_OS_STATE_OS_GP_OFFSET, r3 + mov b0=r2 // save return address + GET_IA64_MCA_DATA(temp1) + ;; + add temp4=temp4, temp1 // &struct ia64_sal_os_state.os_gp + add r12=temp1, temp3 // kernel stack pointer on MCA/INIT stack + add r13=temp1, r3 // set current to start of MCA/INIT stack + ;; + ld8 r1=[temp4] // OS GP from SAL OS state + ;; + DATA_PA_TO_VA(r1,temp1) + DATA_PA_TO_VA(r12,temp2) + DATA_PA_TO_VA(r13,temp3) + ;; + mov IA64_KR(CURRENT)=r13 + + // FIXME: do I need to wire IA64_KR_CURRENT_STACK and IA64_TR_CURRENT_STACK? + + br.sptk b0 + +//EndStub////////////////////////////////////////////////////////////////////// + +#undef ms +#undef regs +#undef temp1 +#undef temp2 +#undef temp3 +#undef temp4 + -GLOBAL_ENTRY(ia64_slave_init_handler) -1: br.sptk 1b -END(ia64_slave_init_handler) +// Support function for mca.c, it is here to avoid using inline asm. Given the +// address of an rnat slot, if that address is below the current ar.bspstore +// then return the contents of that slot, otherwise return the contents of +// ar.rnat. +GLOBAL_ENTRY(ia64_get_rnat) + alloc r14=ar.pfs,1,0,0,0 + mov ar.rsc=0 + ;; + mov r14=ar.bspstore + ;; + cmp.lt p6,p7=in0,r14 + ;; +(p6) ld8 r8=[in0] +(p7) mov r8=ar.rnat + mov ar.rsc=3 + br.ret.sptk.many rp +END(ia64_get_rnat) diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c index abc0113a821df..6e683745af49d 100644 --- a/arch/ia64/kernel/mca_drv.c +++ b/arch/ia64/kernel/mca_drv.c @@ -4,6 +4,8 @@ * * Copyright (C) 2004 FUJITSU LIMITED * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) + * Copyright (C) 2005 Silicon Graphics, Inc + * Copyright (C) 2005 Keith Owens <kaos@sgi.com> */ #include <linux/config.h> #include <linux/types.h> @@ -38,10 +40,6 @@ /* max size of SAL error record (default) */ static int sal_rec_max = 10000; -/* from mca.c */ -static ia64_mca_sal_to_os_state_t *sal_to_os_handoff_state; -static ia64_mca_os_to_sal_state_t *os_to_sal_handoff_state; - /* from mca_drv_asm.S */ extern void *mca_handler_bhhook(void); @@ -316,7 +314,8 @@ init_record_index_pools(void) */ static mca_type_t -is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci) +is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci, + struct ia64_sal_os_state *sos) { pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); @@ -327,7 +326,7 @@ is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci) * Therefore it is local MCA when rendezvous has not been requested. * Failed to rendezvous, the system must be down. */ - switch (sal_to_os_handoff_state->imsto_rendez_state) { + switch (sos->rv_rc) { case -1: /* SAL rendezvous unsuccessful */ return MCA_IS_GLOBAL; case 0: /* SAL rendezvous not required */ @@ -388,7 +387,8 @@ is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci) */ static int -recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci) +recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci, + struct ia64_sal_os_state *sos) { sal_log_mod_error_info_t *smei; pal_min_state_area_t *pmsa; @@ -426,7 +426,7 @@ recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_chec * setup for resume to bottom half of MCA, * "mca_handler_bhhook" */ - pmsa = (pal_min_state_area_t *)(sal_to_os_handoff_state->pal_min_state | (6ul<<61)); + pmsa = sos->pal_min_state; /* pass to bhhook as 1st argument (gr8) */ pmsa->pmsa_gr[8-1] = smei->target_identifier; /* set interrupted return address (but no use) */ @@ -459,7 +459,8 @@ recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_chec */ static int -recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci) +recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci, + struct ia64_sal_os_state *sos) { int status = 0; pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); @@ -469,7 +470,7 @@ recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_ case 1: /* partial read */ case 3: /* full line(cpu) read */ case 9: /* I/O space read */ - status = recover_from_read_error(slidx, peidx, pbci); + status = recover_from_read_error(slidx, peidx, pbci, sos); break; case 0: /* unknown */ case 2: /* partial write */ @@ -508,7 +509,8 @@ recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_ */ static int -recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci) +recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci, + struct ia64_sal_os_state *sos) { pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); @@ -545,7 +547,7 @@ recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t * * This means "there are some platform errors". */ if (platform) - return recover_from_platform_error(slidx, peidx, pbci); + return recover_from_platform_error(slidx, peidx, pbci, sos); /* * On account of strange SAL error record, we cannot recover. */ @@ -562,8 +564,7 @@ recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t * static int mca_try_to_recover(void *rec, - ia64_mca_sal_to_os_state_t *sal_to_os_state, - ia64_mca_os_to_sal_state_t *os_to_sal_state) + struct ia64_sal_os_state *sos) { int platform_err; int n_proc_err; @@ -571,10 +572,6 @@ mca_try_to_recover(void *rec, peidx_table_t peidx; pal_bus_check_info_t pbci; - /* handoff state from/to mca.c */ - sal_to_os_handoff_state = sal_to_os_state; - os_to_sal_handoff_state = os_to_sal_state; - /* Make index of SAL error record */ platform_err = mca_make_slidx(rec, &slidx); @@ -597,11 +594,11 @@ mca_try_to_recover(void *rec, *((u64*)&pbci) = peidx_check_info(&peidx, bus_check, 0); /* Check whether MCA is global or not */ - if (is_mca_global(&peidx, &pbci)) + if (is_mca_global(&peidx, &pbci, sos)) return 0; /* Try to recover a processor error */ - return recover_from_processor_error(platform_err, &slidx, &peidx, &pbci); + return recover_from_processor_error(platform_err, &slidx, &peidx, &pbci, sos); } /* diff --git a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h index 149ad01184550..97a28b8b2dddd 100644 --- a/include/asm-ia64/mca.h +++ b/include/asm-ia64/mca.h @@ -11,8 +11,6 @@ #ifndef _ASM_IA64_MCA_H #define _ASM_IA64_MCA_H -#define IA64_MCA_STACK_SIZE 8192 - #if !defined(__ASSEMBLY__) #include <linux/interrupt.h> @@ -48,7 +46,8 @@ typedef union cmcv_reg_u { enum { IA64_MCA_RENDEZ_CHECKIN_NOTDONE = 0x0, - IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1 + IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1, + IA64_MCA_RENDEZ_CHECKIN_INIT = 0x2, }; /* Information maintained by the MC infrastructure */ @@ -63,18 +62,42 @@ typedef struct ia64_mc_info_s { } ia64_mc_info_t; -typedef struct ia64_mca_sal_to_os_state_s { - u64 imsto_os_gp; /* GP of the os registered with the SAL */ - u64 imsto_pal_proc; /* PAL_PROC entry point - physical addr */ - u64 imsto_sal_proc; /* SAL_PROC entry point - physical addr */ - u64 imsto_sal_gp; /* GP of the SAL - physical */ - u64 imsto_rendez_state; /* Rendez state information */ - u64 imsto_sal_check_ra; /* Return address in SAL_CHECK while going - * back to SAL from OS after MCA handling. - */ - u64 pal_min_state; /* from PAL in r17 */ - u64 proc_state_param; /* from PAL in r18. See SDV 2:268 11.3.2.1 */ -} ia64_mca_sal_to_os_state_t; +/* Handover state from SAL to OS and vice versa, for both MCA and INIT events. + * Besides the handover state, it also contains some saved registers from the + * time of the event. + * Note: mca_asm.S depends on the precise layout of this structure. + */ + +struct ia64_sal_os_state { + /* SAL to OS, must be at offset 0 */ + u64 os_gp; /* GP of the os registered with the SAL, physical */ + u64 pal_proc; /* PAL_PROC entry point, physical */ + u64 sal_proc; /* SAL_PROC entry point, physical */ + u64 rv_rc; /* MCA - Rendezvous state, INIT - reason code */ + u64 proc_state_param; /* from R18 */ + u64 monarch; /* 1 for a monarch event, 0 for a slave */ + /* common, must follow SAL to OS */ + u64 sal_ra; /* Return address in SAL, physical */ + u64 sal_gp; /* GP of the SAL - physical */ + pal_min_state_area_t *pal_min_state; /* from R17. physical in asm, virtual in C */ + u64 prev_IA64_KR_CURRENT; /* previous value of IA64_KR(CURRENT) */ + struct task_struct *prev_task; /* previous task, NULL if it is not useful */ + /* Some interrupt registers are not saved in minstate, pt_regs or + * switch_stack. Because MCA/INIT can occur when interrupts are + * disabled, we need to save the additional interrupt registers over + * MCA/INIT and resume. + */ + u64 isr; + u64 ifa; + u64 itir; + u64 iipa; + u64 iim; + u64 iha; + /* OS to SAL, must follow common */ + u64 os_status; /* OS status to SAL, enum below */ + u64 context; /* 0 if return to same context + 1 if return to new context */ +}; enum { IA64_MCA_CORRECTED = 0x0, /* Error has been corrected by OS_MCA */ @@ -83,36 +106,22 @@ enum { IA64_MCA_HALT = -3 /* System to be halted by SAL */ }; +enum { + IA64_INIT_RESUME = 0x0, /* Resume after return from INIT */ + IA64_INIT_WARM_BOOT = -1, /* Warm boot of the system need from SAL */ +}; + enum { IA64_MCA_SAME_CONTEXT = 0x0, /* SAL to return to same context */ IA64_MCA_NEW_CONTEXT = -1 /* SAL to return to new context */ }; -typedef struct ia64_mca_os_to_sal_state_s { - u64 imots_os_status; /* OS status to SAL as to what happened - * with the MCA handling. - */ - u64 imots_sal_gp; /* GP of the SAL - physical */ - u64 imots_context; /* 0 if return to same context - 1 if return to new context */ - u64 *imots_new_min_state; /* Pointer to structure containing - * new values of registers in the min state - * save area. - */ - u64 imots_sal_check_ra; /* Return address in SAL_CHECK while going - * back to SAL from OS after MCA handling. - */ -} ia64_mca_os_to_sal_state_t; - /* Per-CPU MCA state that is too big for normal per-CPU variables. */ struct ia64_mca_cpu { - u64 stack[IA64_MCA_STACK_SIZE/8]; /* MCA memory-stack */ - u64 proc_state_dump[512]; - u64 stackframe[32]; - u64 rbstore[IA64_MCA_STACK_SIZE/8]; /* MCA reg.-backing store */ + u64 mca_stack[KERNEL_STACK_SIZE/8]; u64 init_stack[KERNEL_STACK_SIZE/8]; -} __attribute__ ((aligned(16))); +}; /* Array of physical addresses of each CPU's MCA area. */ extern unsigned long __per_cpu_mca[NR_CPUS]; @@ -121,12 +130,29 @@ extern void ia64_mca_init(void); extern void ia64_mca_cpu_init(void *); extern void ia64_os_mca_dispatch(void); extern void ia64_os_mca_dispatch_end(void); -extern void ia64_mca_ucmc_handler(void); +extern void ia64_mca_ucmc_handler(struct pt_regs *, struct ia64_sal_os_state *); +extern void ia64_init_handler(struct pt_regs *, + struct switch_stack *, + struct ia64_sal_os_state *); extern void ia64_monarch_init_handler(void); extern void ia64_slave_init_handler(void); extern void ia64_mca_cmc_vector_setup(void); -extern int ia64_reg_MCA_extension(void*); +extern int ia64_reg_MCA_extension(int (*fn)(void *, struct ia64_sal_os_state *)); extern void ia64_unreg_MCA_extension(void); +extern u64 ia64_get_rnat(u64 *); + +#else /* __ASSEMBLY__ */ + +#define IA64_MCA_CORRECTED 0x0 /* Error has been corrected by OS_MCA */ +#define IA64_MCA_WARM_BOOT -1 /* Warm boot of the system need from SAL */ +#define IA64_MCA_COLD_BOOT -2 /* Cold boot of the system need from SAL */ +#define IA64_MCA_HALT -3 /* System to be halted by SAL */ + +#define IA64_INIT_RESUME 0x0 /* Resume after return from INIT */ +#define IA64_INIT_WARM_BOOT -1 /* Warm boot of the system need from SAL */ + +#define IA64_MCA_SAME_CONTEXT 0x0 /* SAL to return to same context */ +#define IA64_MCA_NEW_CONTEXT -1 /* SAL to return to new context */ #endif /* !__ASSEMBLY__ */ #endif /* _ASM_IA64_MCA_H */ diff --git a/include/asm-ia64/mca_asm.h b/include/asm-ia64/mca_asm.h index 836953e0f91f6..27c9203d8ce31 100644 --- a/include/asm-ia64/mca_asm.h +++ b/include/asm-ia64/mca_asm.h @@ -8,6 +8,8 @@ * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 2002 Intel Corp. * Copyright (C) 2002 Jenna Hall <jenna.s.hall@intel.com> + * Copyright (C) 2005 Silicon Graphics, Inc + * Copyright (C) 2005 Keith Owens <kaos@sgi.com> */ #ifndef _ASM_IA64_MCA_ASM_H #define _ASM_IA64_MCA_ASM_H @@ -207,106 +209,33 @@ ;; /* - * The following offsets capture the order in which the - * RSE related registers from the old context are - * saved onto the new stack frame. + * The MCA and INIT stacks in struct ia64_mca_cpu look like normal kernel + * stacks, except that the SAL/OS state and a switch_stack are stored near the + * top of the MCA/INIT stack. To support concurrent entry to MCA or INIT, as + * well as MCA over INIT, each event needs its own SAL/OS state. All entries + * are 16 byte aligned. * - * +-----------------------+ - * |NDIRTY [BSP - BSPSTORE]| - * +-----------------------+ - * | RNAT | - * +-----------------------+ - * | BSPSTORE | - * +-----------------------+ - * | IFS | - * +-----------------------+ - * | PFS | - * +-----------------------+ - * | RSC | - * +-----------------------+ <-------- Bottom of new stack frame + * +---------------------------+ + * | pt_regs | + * +---------------------------+ + * | switch_stack | + * +---------------------------+ + * | SAL/OS state | + * +---------------------------+ + * | 16 byte scratch area | + * +---------------------------+ <-------- SP at start of C MCA handler + * | ..... | + * +---------------------------+ + * | RBS for MCA/INIT handler | + * +---------------------------+ + * | struct task for MCA/INIT | + * +---------------------------+ <-------- Bottom of MCA/INIT stack */ -#define rse_rsc_offset 0 -#define rse_pfs_offset (rse_rsc_offset+0x08) -#define rse_ifs_offset (rse_pfs_offset+0x08) -#define rse_bspstore_offset (rse_ifs_offset+0x08) -#define rse_rnat_offset (rse_bspstore_offset+0x08) -#define rse_ndirty_offset (rse_rnat_offset+0x08) -/* - * rse_switch_context - * - * 1. Save old RSC onto the new stack frame - * 2. Save PFS onto new stack frame - * 3. Cover the old frame and start a new frame. - * 4. Save IFS onto new stack frame - * 5. Save the old BSPSTORE on the new stack frame - * 6. Save the old RNAT on the new stack frame - * 7. Write BSPSTORE with the new backing store pointer - * 8. Read and save the new BSP to calculate the #dirty registers - * NOTE: Look at pages 11-10, 11-11 in PRM Vol 2 - */ -#define rse_switch_context(temp,p_stackframe,p_bspstore) \ - ;; \ - mov temp=ar.rsc;; \ - st8 [p_stackframe]=temp,8;; \ - mov temp=ar.pfs;; \ - st8 [p_stackframe]=temp,8; \ - cover ;; \ - mov temp=cr.ifs;; \ - st8 [p_stackframe]=temp,8;; \ - mov temp=ar.bspstore;; \ - st8 [p_stackframe]=temp,8;; \ - mov temp=ar.rnat;; \ - st8 [p_stackframe]=temp,8; \ - mov ar.bspstore=p_bspstore;; \ - mov temp=ar.bsp;; \ - sub temp=temp,p_bspstore;; \ - st8 [p_stackframe]=temp,8;; - -/* - * rse_return_context - * 1. Allocate a zero-sized frame - * 2. Store the number of dirty registers RSC.loadrs field - * 3. Issue a loadrs to insure that any registers from the interrupted - * context which were saved on the new stack frame have been loaded - * back into the stacked registers - * 4. Restore BSPSTORE - * 5. Restore RNAT - * 6. Restore PFS - * 7. Restore IFS - * 8. Restore RSC - * 9. Issue an RFI - */ -#define rse_return_context(psr_mask_reg,temp,p_stackframe) \ - ;; \ - alloc temp=ar.pfs,0,0,0,0; \ - add p_stackframe=rse_ndirty_offset,p_stackframe;; \ - ld8 temp=[p_stackframe];; \ - shl temp=temp,16;; \ - mov ar.rsc=temp;; \ - loadrs;; \ - add p_stackframe=-rse_ndirty_offset+rse_bspstore_offset,p_stackframe;;\ - ld8 temp=[p_stackframe];; \ - mov ar.bspstore=temp;; \ - add p_stackframe=-rse_bspstore_offset+rse_rnat_offset,p_stackframe;;\ - ld8 temp=[p_stackframe];; \ - mov ar.rnat=temp;; \ - add p_stackframe=-rse_rnat_offset+rse_pfs_offset,p_stackframe;; \ - ld8 temp=[p_stackframe];; \ - mov ar.pfs=temp;; \ - add p_stackframe=-rse_pfs_offset+rse_ifs_offset,p_stackframe;; \ - ld8 temp=[p_stackframe];; \ - mov cr.ifs=temp;; \ - add p_stackframe=-rse_ifs_offset+rse_rsc_offset,p_stackframe;; \ - ld8 temp=[p_stackframe];; \ - mov ar.rsc=temp ; \ - mov temp=psr;; \ - or temp=temp,psr_mask_reg;; \ - mov cr.ipsr=temp;; \ - mov temp=ip;; \ - add temp=0x30,temp;; \ - mov cr.iip=temp;; \ - srlz.i;; \ - rfi;; +#define ALIGN16(x) ((x)&~15) +#define MCA_PT_REGS_OFFSET ALIGN16(KERNEL_STACK_SIZE-IA64_PT_REGS_SIZE) +#define MCA_SWITCH_STACK_OFFSET ALIGN16(MCA_PT_REGS_OFFSET-IA64_SWITCH_STACK_SIZE) +#define MCA_SOS_OFFSET ALIGN16(MCA_SWITCH_STACK_OFFSET-IA64_SAL_OS_STATE_SIZE) +#define MCA_SP_OFFSET ALIGN16(MCA_SOS_OFFSET-16) #endif /* _ASM_IA64_MCA_ASM_H */ -- GitLab From 05f335ea04881ecb912b572c83e281a016149169 Mon Sep 17 00:00:00 2001 From: Keith Owens <kaos@sgi.com> Date: Sun, 11 Sep 2005 17:23:42 +1000 Subject: [PATCH 457/563] [IA64] MCA/INIT: remove the physical mode path from minstate.h Remove the physical mode path from minstate.h. Signed-off-by: Keith Owens <kaos@sgi.com> Signed-off-by: Tony Luck <tony.luck@intel.com> --- arch/ia64/kernel/ivt.S | 1 - arch/ia64/kernel/minstate.h | 88 ++++++++----------------------------- 2 files changed, 18 insertions(+), 71 deletions(-) diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index 3ba8384cb43de..c13ca0d49c4a0 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -69,7 +69,6 @@ # define DBG_FAULT(i) #endif -#define MINSTATE_VIRT /* needed by minstate.h */ #include "minstate.h" #define FAULT(n) \ diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h index f6d8a010d99be..85ed54179afa5 100644 --- a/arch/ia64/kernel/minstate.h +++ b/arch/ia64/kernel/minstate.h @@ -4,73 +4,6 @@ #include "entry.h" -/* - * For ivt.s we want to access the stack virtually so we don't have to disable translation - * on interrupts. - * - * On entry: - * r1: pointer to current task (ar.k6) - */ -#define MINSTATE_START_SAVE_MIN_VIRT \ -(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ - ;; \ -(pUStk) mov.m r24=ar.rnat; \ -(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ -(pKStk) mov r1=sp; /* get sp */ \ - ;; \ -(pUStk) lfetch.fault.excl.nt1 [r22]; \ -(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ - ;; \ -(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ -(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ - ;; \ -(pUStk) mov r18=ar.bsp; \ -(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ - -#define MINSTATE_END_SAVE_MIN_VIRT \ - bsw.1; /* switch back to bank 1 (must be last in insn group) */ \ - ;; - -/* - * For mca_asm.S we want to access the stack physically since the state is saved before we - * go virtual and don't want to destroy the iip or ipsr. - */ -#define MINSTATE_START_SAVE_MIN_PHYS \ -(pKStk) mov r3=IA64_KR(PER_CPU_DATA);; \ -(pKStk) addl r3=THIS_CPU(ia64_mca_data),r3;; \ -(pKStk) ld8 r3 = [r3];; \ -(pKStk) addl r3=IA64_MCA_CPU_INIT_STACK_OFFSET,r3;; \ -(pKStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r3; \ -(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ -(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ - ;; \ -(pUStk) mov r24=ar.rnat; \ -(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ -(pUStk) dep r22=-1,r22,61,3; /* compute kernel virtual addr of RBS */ \ - ;; \ -(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ - ;; \ -(pUStk) mov r18=ar.bsp; \ -(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ - -#define MINSTATE_END_SAVE_MIN_PHYS \ - dep r12=-1,r12,61,3; /* make sp a kernel virtual address */ \ - ;; - -#ifdef MINSTATE_VIRT -# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT) -# define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_VIRT -# define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_VIRT -#endif - -#ifdef MINSTATE_PHYS -# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT);; tpa reg=reg -# define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_PHYS -# define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_PHYS -#endif - /* * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves * the minimum state necessary that allows us to turn psr.ic back @@ -97,7 +30,7 @@ * we can pass interruption state as arguments to a handler. */ #define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ - MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \ + mov r16=IA64_KR(CURRENT); /* M */ \ mov r27=ar.rsc; /* M */ \ mov r20=r1; /* A */ \ mov r25=ar.unat; /* M */ \ @@ -118,7 +51,21 @@ SAVE_IFS; \ cmp.eq pKStk,pUStk=r0,r17; /* are we in kernel mode already? */ \ ;; \ - MINSTATE_START_SAVE_MIN \ +(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ + ;; \ +(pUStk) mov.m r24=ar.rnat; \ +(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ +(pKStk) mov r1=sp; /* get sp */ \ + ;; \ +(pUStk) lfetch.fault.excl.nt1 [r22]; \ +(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ +(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ + ;; \ +(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ +(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ + ;; \ +(pUStk) mov r18=ar.bsp; \ +(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ adds r17=2*L1_CACHE_BYTES,r1; /* really: biggest cache-line size */ \ adds r16=PT(CR_IPSR),r1; \ ;; \ @@ -181,7 +128,8 @@ EXTRA; \ movl r1=__gp; /* establish kernel global pointer */ \ ;; \ - MINSTATE_END_SAVE_MIN + bsw.1; /* switch back to bank 1 (must be last in insn group) */ \ + ;; /* * SAVE_REST saves the remainder of pt_regs (with psr.ic on). -- GitLab From 49a28cc8fd26f5317c47a9aeb2bdd1c33e21738e Mon Sep 17 00:00:00 2001 From: Keith Owens <kaos@sgi.com> Date: Sun, 11 Sep 2005 17:24:42 +1000 Subject: [PATCH 458/563] [IA64] MCA/INIT: remove obsolete unwind code Delete the special case unwind code that was only used by the old MCA/INIT handler. Signed-off-by: Keith Owens <kaos@sgi.com> Signed-off-by: Tony Luck <tony.luck@intel.com> --- arch/ia64/kernel/unwind.c | 22 ---------------------- include/asm-ia64/unwind.h | 7 ------- 2 files changed, 29 deletions(-) diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index 3288be47bc758..93d5a3b41f69e 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -2019,28 +2019,6 @@ init_frame_info (struct unw_frame_info *info, struct task_struct *t, STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags)); } -void -unw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t, - struct pt_regs *pt, struct switch_stack *sw) -{ - unsigned long sof; - - init_frame_info(info, t, sw, pt->r12); - info->cfm_loc = &pt->cr_ifs; - info->unat_loc = &pt->ar_unat; - info->pfs_loc = &pt->ar_pfs; - sof = *info->cfm_loc & 0x7f; - info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sof); - info->ip = pt->cr_iip + ia64_psr(pt)->ri; - info->pt = (unsigned long) pt; - UNW_DPRINT(3, "unwind.%s:\n" - " bsp 0x%lx\n" - " sof 0x%lx\n" - " ip 0x%lx\n", - __FUNCTION__, info->bsp, sof, info->ip); - find_save_locs(info); -} - void unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw) { diff --git a/include/asm-ia64/unwind.h b/include/asm-ia64/unwind.h index 61426ad3ecdb8..5df0276b0493e 100644 --- a/include/asm-ia64/unwind.h +++ b/include/asm-ia64/unwind.h @@ -114,13 +114,6 @@ extern void unw_remove_unwind_table (void *handle); */ extern void unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t); -/* - * Prepare to unwind from interruption. The pt-regs and switch-stack structures must have - * be "adjacent" (no state modifications between pt-regs and switch-stack). - */ -extern void unw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t, - struct pt_regs *pt, struct switch_stack *sw); - extern void unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw); -- GitLab From 2af6921f6382456ed69163be9d2ee2c339134496 Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 459/563] [PATCH] m68knommu: config support for FEC eth of 523x Coldfire processor family Add configuration support for the FEC ethernet controller in the Freescale 523x processor family. Also add and option to configure the second FEC controller on some Freescale processors. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/net/Kconfig | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6bb9232514b4e..54fff9c2e8028 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1738,11 +1738,18 @@ config 68360_ENET the Motorola 68360 processor. config FEC - bool "FEC ethernet controller (of ColdFire 5272)" - depends on M5272 || M5282 + bool "FEC ethernet controller (of ColdFire CPUs)" + depends on M523x || M527x || M5272 || M528x help Say Y here if you want to use the built-in 10/100 Fast ethernet - controller on the Motorola ColdFire 5272 processor. + controller on some Motorola ColdFire processors. + +config FEC2 + bool "Second FEC ethernet controller (on some ColdFire CPUs)" + depends on FEC + help + Say Y here if you want to use the second built-in 10/100 Fast + ethernet controller on some Motorola ColdFire processors. config NE_H8300 tristate "NE2000 compatible support for H8/300" -- GitLab From 7dd6a2aa27a7a8036fbaf60cbce38a64128d1d4d Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 460/563] [PATCH] m68knommu: ColdFire FEC eth driver improvements A few improvements to the Freescale/ColdFire FEC driver: . some formatting cleanups . add support for the FEC device in the ColdFire 523x processor family . add support for MAC address setting on MOD5272 and M5272C3 boards . don't re-read the PHY status register many times . ack status interrupt before reading status register . move printing init message to after full init (so that the ethX name is filled out for printing) Some parts of this patch submitted by Philippe De Muyter <phdm@macqel.be> Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/net/fec.c | 478 ++++++++++++++++++++++++---------------------- 1 file changed, 248 insertions(+), 230 deletions(-) diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 2c7008491378f..85504fb900dab 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -8,7 +8,7 @@ * describes connections using the internal parallel port I/O, which * is basically all of Port D. * - * Right now, I am very watseful with the buffers. I allocate memory + * Right now, I am very wasteful with the buffers. I allocate memory * pages and then divide them into 2K frame buffers. This way I know I * have buffers large enough to hold one frame within one buffer descriptor. * Once I get this working, I will use 64 or 128 byte CPM buffers, which @@ -19,7 +19,10 @@ * Copyright (c) 2000 Ericsson Radio Systems AB. * * Support for FEC controller of ColdFire/5270/5271/5272/5274/5275/5280/5282. - * Copyrught (c) 2001-2004 Greg Ungerer (gerg@snapgear.com) + * Copyright (c) 2001-2004 Greg Ungerer (gerg@snapgear.com) + * + * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) + * Copyright (c) 2004-2005 Macq Electronique SA. */ #include <linux/config.h> @@ -46,7 +49,8 @@ #include <asm/io.h> #include <asm/pgtable.h> -#if defined(CONFIG_M527x) || defined(CONFIG_M5272) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ + defined(CONFIG_M5272) || defined(CONFIG_M528x) #include <asm/coldfire.h> #include <asm/mcfsim.h> #include "fec.h" @@ -71,7 +75,7 @@ static unsigned int fec_hw[] = { #elif defined(CONFIG_M527x) (MCF_MBAR + 0x1000), (MCF_MBAR + 0x1800), -#elif defined(CONFIG_M528x) +#elif defined(CONFIG_M523x) || defined(CONFIG_M528x) (MCF_MBAR + 0x1000), #else &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), @@ -94,12 +98,14 @@ static unsigned char fec_mac_default[] = { #define FEC_FLASHMAC 0xffe04000 #elif defined(CONFIG_CANCam) #define FEC_FLASHMAC 0xf0020000 +#elif defined (CONFIG_M5272C3) +#define FEC_FLASHMAC (0xffe04000 + 4) +#elif defined(CONFIG_MOD5272) +#define FEC_FLASHMAC 0xffc0406b #else #define FEC_FLASHMAC 0 #endif -unsigned char *fec_flashmac = (unsigned char *) FEC_FLASHMAC; - /* Forward declarations of some structures to support different PHYs */ @@ -158,7 +164,7 @@ typedef struct { * size bits. Other FEC hardware does not, so we need to take that into * account when setting it. */ -#if defined(CONFIG_M527x) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) #else #define OPT_FRAME_SIZE 0 @@ -196,7 +202,7 @@ struct fec_enet_private { uint phy_id_done; uint phy_status; uint phy_speed; - phy_info_t *phy; + phy_info_t const *phy; struct work_struct phy_task; uint sequence_done; @@ -209,7 +215,6 @@ struct fec_enet_private { int link; int old_link; int full_duplex; - unsigned char mac_addr[ETH_ALEN]; }; static int fec_enet_open(struct net_device *dev); @@ -237,10 +242,10 @@ typedef struct mii_list { } mii_list_t; #define NMII 20 -mii_list_t mii_cmds[NMII]; -mii_list_t *mii_free; -mii_list_t *mii_head; -mii_list_t *mii_tail; +static mii_list_t mii_cmds[NMII]; +static mii_list_t *mii_free; +static mii_list_t *mii_head; +static mii_list_t *mii_tail; static int mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *)); @@ -425,7 +430,7 @@ fec_timeout(struct net_device *dev) } } #endif - fec_restart(dev, 0); + fec_restart(dev, fep->full_duplex); netif_wake_queue(dev); } @@ -757,45 +762,52 @@ static void mii_parse_sr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); + status = *s & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); if (mii_reg & 0x0004) - *s |= PHY_STAT_LINK; + status |= PHY_STAT_LINK; if (mii_reg & 0x0010) - *s |= PHY_STAT_FAULT; + status |= PHY_STAT_FAULT; if (mii_reg & 0x0020) - *s |= PHY_STAT_ANC; + status |= PHY_STAT_ANC; + + *s = status; } static void mii_parse_cr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP); + status = *s & ~(PHY_CONF_ANE | PHY_CONF_LOOP); if (mii_reg & 0x1000) - *s |= PHY_CONF_ANE; + status |= PHY_CONF_ANE; if (mii_reg & 0x4000) - *s |= PHY_CONF_LOOP; + status |= PHY_CONF_LOOP; + *s = status; } static void mii_parse_anar(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_CONF_SPMASK); + status = *s & ~(PHY_CONF_SPMASK); if (mii_reg & 0x0020) - *s |= PHY_CONF_10HDX; + status |= PHY_CONF_10HDX; if (mii_reg & 0x0040) - *s |= PHY_CONF_10FDX; + status |= PHY_CONF_10FDX; if (mii_reg & 0x0080) - *s |= PHY_CONF_100HDX; + status |= PHY_CONF_100HDX; if (mii_reg & 0x00100) - *s |= PHY_CONF_100FDX; + status |= PHY_CONF_100FDX; + *s = status; } /* ------------------------------------------------------------------------- */ @@ -811,37 +823,34 @@ static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK); - + status = *s & ~(PHY_STAT_SPMASK); if (mii_reg & 0x0800) { if (mii_reg & 0x1000) - *s |= PHY_STAT_100FDX; + status |= PHY_STAT_100FDX; else - *s |= PHY_STAT_100HDX; + status |= PHY_STAT_100HDX; } else { if (mii_reg & 0x1000) - *s |= PHY_STAT_10FDX; + status |= PHY_STAT_10FDX; else - *s |= PHY_STAT_10HDX; + status |= PHY_STAT_10HDX; } + *s = status; } -static phy_info_t phy_info_lxt970 = { - 0x07810000, - "LXT970", - - (const phy_cmd_t []) { /* config */ +static phy_cmd_t const phy_cmd_lxt970_config[] = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt970_startup[] = { /* enable interrupts */ { mk_mii_write(MII_LXT970_IER, 0x0002), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_lxt970_ack_int[] = { /* read SR and ISR to acknowledge */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_LXT970_ISR), NULL }, @@ -849,11 +858,18 @@ static phy_info_t phy_info_lxt970 = { /* find out the current status */ { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_LXT970_IER, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_lxt970 = { + .id = 0x07810000, + .name = "LXT970", + .config = phy_cmd_lxt970_config, + .startup = phy_cmd_lxt970_startup, + .ack_int = phy_cmd_lxt970_ack_int, + .shutdown = phy_cmd_lxt970_shutdown }; /* ------------------------------------------------------------------------- */ @@ -878,45 +894,44 @@ static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); + status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); if (mii_reg & 0x0400) { fep->link = 1; - *s |= PHY_STAT_LINK; + status |= PHY_STAT_LINK; } else { fep->link = 0; } if (mii_reg & 0x0080) - *s |= PHY_STAT_ANC; + status |= PHY_STAT_ANC; if (mii_reg & 0x4000) { if (mii_reg & 0x0200) - *s |= PHY_STAT_100FDX; + status |= PHY_STAT_100FDX; else - *s |= PHY_STAT_100HDX; + status |= PHY_STAT_100HDX; } else { if (mii_reg & 0x0200) - *s |= PHY_STAT_10FDX; + status |= PHY_STAT_10FDX; else - *s |= PHY_STAT_10HDX; + status |= PHY_STAT_10HDX; } if (mii_reg & 0x0008) - *s |= PHY_STAT_FAULT; -} + status |= PHY_STAT_FAULT; -static phy_info_t phy_info_lxt971 = { - 0x0001378e, - "LXT971", + *s = status; +} - (const phy_cmd_t []) { /* config */ - /* limit to 10MBit because my protorype board +static phy_cmd_t const phy_cmd_lxt971_config[] = { + /* limit to 10MBit because my prototype board * doesn't work with 100. */ { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt971_startup[] = { /* enable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_write(MII_LXT971_LCR, 0xd422), NULL }, /* LED config */ @@ -925,19 +940,26 @@ static phy_info_t phy_info_lxt971 = { * read here to get a valid value in ack_int */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_lxt971_ack_int[] = { + /* acknowledge the int before reading status ! */ + { mk_mii_read(MII_LXT971_ISR), NULL }, /* find out the current status */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, - /* we only need to read ISR to acknowledge */ - { mk_mii_read(MII_LXT971_ISR), NULL }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_lxt971 = { + .id = 0x0001378e, + .name = "LXT971", + .config = phy_cmd_lxt971_config, + .startup = phy_cmd_lxt971_startup, + .ack_int = phy_cmd_lxt971_ack_int, + .shutdown = phy_cmd_lxt971_shutdown }; /* ------------------------------------------------------------------------- */ @@ -956,22 +978,21 @@ static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK); + status = *s & ~(PHY_STAT_SPMASK); switch((mii_reg >> 2) & 7) { - case 1: *s |= PHY_STAT_10HDX; break; - case 2: *s |= PHY_STAT_100HDX; break; - case 5: *s |= PHY_STAT_10FDX; break; - case 6: *s |= PHY_STAT_100FDX; break; - } + case 1: status |= PHY_STAT_10HDX; break; + case 2: status |= PHY_STAT_100HDX; break; + case 5: status |= PHY_STAT_10FDX; break; + case 6: status |= PHY_STAT_100FDX; break; } -static phy_info_t phy_info_qs6612 = { - 0x00181440, - "QS6612", - - (const phy_cmd_t []) { /* config */ + *s = status; +} + +static phy_cmd_t const phy_cmd_qs6612_config[] = { /* The PHY powers up isolated on the RPX, * so send a command to allow operation. */ @@ -981,13 +1002,13 @@ static phy_info_t phy_info_qs6612 = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_qs6612_startup[] = { /* enable interrupts */ { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_qs6612_ack_int[] = { /* we need to read ISR, SR and ANER to acknowledge */ { mk_mii_read(MII_QS6612_ISR), NULL }, { mk_mii_read(MII_REG_SR), mii_parse_sr }, @@ -996,11 +1017,18 @@ static phy_info_t phy_info_qs6612 = { /* read pcr to get info */ { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_qs6612 = { + .id = 0x00181440, + .name = "QS6612", + .config = phy_cmd_qs6612_config, + .startup = phy_cmd_qs6612_startup, + .ack_int = phy_cmd_qs6612_ack_int, + .shutdown = phy_cmd_qs6612_shutdown }; /* ------------------------------------------------------------------------- */ @@ -1020,49 +1048,54 @@ static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK | PHY_STAT_ANC); + status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC); if (mii_reg & 0x0080) - *s |= PHY_STAT_ANC; + status |= PHY_STAT_ANC; if (mii_reg & 0x0400) - *s |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX); + status |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX); else - *s |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); + status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); + + *s = status; } -static phy_info_t phy_info_am79c874 = { - 0x00022561, - "AM79C874", - - (const phy_cmd_t []) { /* config */ - /* limit to 10MBit because my protorype board - * doesn't work with 100. */ +static phy_cmd_t const phy_cmd_am79c874_config[] = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_am79c874_startup[] = { /* enable interrupts */ { mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_am79c874_ack_int[] = { /* find out the current status */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, /* we only need to read ISR to acknowledge */ { mk_mii_read(MII_AM79C874_ICSR), NULL }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_am79c874 = { + .id = 0x00022561, + .name = "AM79C874", + .config = phy_cmd_am79c874_config, + .startup = phy_cmd_am79c874_startup, + .ack_int = phy_cmd_am79c874_ack_int, + .shutdown = phy_cmd_am79c874_shutdown }; + /* ------------------------------------------------------------------------- */ /* Kendin KS8721BL phy */ @@ -1072,37 +1105,40 @@ static phy_info_t phy_info_am79c874 = { #define MII_KS8721BL_ICSR 22 #define MII_KS8721BL_PHYCR 31 -static phy_info_t phy_info_ks8721bl = { - 0x00022161, - "KS8721BL", - - (const phy_cmd_t []) { /* config */ +static phy_cmd_t const phy_cmd_ks8721bl_config[] = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup */ + }; +static phy_cmd_t const phy_cmd_ks8721bl_startup[] = { /* enable interrupts */ { mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = { /* find out the current status */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, /* we only need to read ISR to acknowledge */ { mk_mii_read(MII_KS8721BL_ICSR), NULL }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown */ + }; +static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_ks8721bl = { + .id = 0x00022161, + .name = "KS8721BL", + .config = phy_cmd_ks8721bl_config, + .startup = phy_cmd_ks8721bl_startup, + .ack_int = phy_cmd_ks8721bl_ack_int, + .shutdown = phy_cmd_ks8721bl_shutdown }; /* ------------------------------------------------------------------------- */ -static phy_info_t *phy_info[] = { +static phy_info_t const * const phy_info[] = { &phy_info_lxt970, &phy_info_lxt971, &phy_info_qs6612, @@ -1129,16 +1165,23 @@ mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs); static void __inline__ fec_request_intrs(struct net_device *dev) { volatile unsigned long *icrp; + static const struct idesc { + char *name; + unsigned short irq; + irqreturn_t (*handler)(int, void *, struct pt_regs *); + } *idp, id[] = { + { "fec(RX)", 86, fec_enet_interrupt }, + { "fec(TX)", 87, fec_enet_interrupt }, + { "fec(OTHER)", 88, fec_enet_interrupt }, + { "fec(MII)", 66, mii_link_interrupt }, + { NULL }, + }; /* Setup interrupt handlers. */ - if (request_irq(86, fec_enet_interrupt, 0, "fec(RX)", dev) != 0) - printk("FEC: Could not allocate FEC(RC) IRQ(86)!\n"); - if (request_irq(87, fec_enet_interrupt, 0, "fec(TX)", dev) != 0) - printk("FEC: Could not allocate FEC(RC) IRQ(87)!\n"); - if (request_irq(88, fec_enet_interrupt, 0, "fec(OTHER)", dev) != 0) - printk("FEC: Could not allocate FEC(OTHER) IRQ(88)!\n"); - if (request_irq(66, mii_link_interrupt, 0, "fec(MII)", dev) != 0) - printk("FEC: Could not allocate MII IRQ(66)!\n"); + for (idp = id; idp->name; idp++) { + if (request_irq(idp->irq, idp->handler, 0, idp->name, dev) != 0) + printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, idp->irq); + } /* Unmask interrupt at ColdFire 5272 SIM */ icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3); @@ -1169,17 +1212,16 @@ static void __inline__ fec_get_mac(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile fec_t *fecp; - unsigned char *iap, tmpaddr[6]; - int i; + unsigned char *iap, tmpaddr[ETH_ALEN]; fecp = fep->hwp; - if (fec_flashmac) { + if (FEC_FLASHMAC) { /* * Get MAC address from FLASH. * If it is all 1's or 0's, use the default. */ - iap = fec_flashmac; + iap = (unsigned char *)FEC_FLASHMAC; if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) iap = fec_mac_default; @@ -1192,14 +1234,11 @@ static void __inline__ fec_get_mac(struct net_device *dev) iap = &tmpaddr[0]; } - for (i=0; i<ETH_ALEN; i++) - dev->dev_addr[i] = fep->mac_addr[i] = *iap++; + memcpy(dev->dev_addr, iap, ETH_ALEN); /* Adjust MAC if using default MAC address */ - if (iap == fec_mac_default) { - dev->dev_addr[ETH_ALEN-1] = fep->mac_addr[ETH_ALEN-1] = - iap[ETH_ALEN-1] + fep->index; - } + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; } static void __inline__ fec_enable_phy_intr(void) @@ -1234,48 +1273,44 @@ static void __inline__ fec_uncache(unsigned long addr) /* ------------------------------------------------------------------------- */ -#elif defined(CONFIG_M527x) || defined(CONFIG_M528x) +#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) /* - * Code specific to Coldfire 5270/5271/5274/5275 and 5280/5282 setups. + * Code specific to Coldfire 5230/5231/5232/5234/5235, + * the 5270/5271/5274/5275 and 5280/5282 setups. */ static void __inline__ fec_request_intrs(struct net_device *dev) { struct fec_enet_private *fep; int b; + static const struct idesc { + char *name; + unsigned short irq; + } *idp, id[] = { + { "fec(TXF)", 23 }, + { "fec(TXB)", 24 }, + { "fec(TXFIFO)", 25 }, + { "fec(TXCR)", 26 }, + { "fec(RXF)", 27 }, + { "fec(RXB)", 28 }, + { "fec(MII)", 29 }, + { "fec(LC)", 30 }, + { "fec(HBERR)", 31 }, + { "fec(GRA)", 32 }, + { "fec(EBERR)", 33 }, + { "fec(BABT)", 34 }, + { "fec(BABR)", 35 }, + { NULL }, + }; fep = netdev_priv(dev); b = (fep->index) ? 128 : 64; /* Setup interrupt handlers. */ - if (request_irq(b+23, fec_enet_interrupt, 0, "fec(TXF)", dev) != 0) - printk("FEC: Could not allocate FEC(TXF) IRQ(%d+23)!\n", b); - if (request_irq(b+24, fec_enet_interrupt, 0, "fec(TXB)", dev) != 0) - printk("FEC: Could not allocate FEC(TXB) IRQ(%d+24)!\n", b); - if (request_irq(b+25, fec_enet_interrupt, 0, "fec(TXFIFO)", dev) != 0) - printk("FEC: Could not allocate FEC(TXFIFO) IRQ(%d+25)!\n", b); - if (request_irq(b+26, fec_enet_interrupt, 0, "fec(TXCR)", dev) != 0) - printk("FEC: Could not allocate FEC(TXCR) IRQ(%d+26)!\n", b); - - if (request_irq(b+27, fec_enet_interrupt, 0, "fec(RXF)", dev) != 0) - printk("FEC: Could not allocate FEC(RXF) IRQ(%d+27)!\n", b); - if (request_irq(b+28, fec_enet_interrupt, 0, "fec(RXB)", dev) != 0) - printk("FEC: Could not allocate FEC(RXB) IRQ(%d+28)!\n", b); - - if (request_irq(b+29, fec_enet_interrupt, 0, "fec(MII)", dev) != 0) - printk("FEC: Could not allocate FEC(MII) IRQ(%d+29)!\n", b); - if (request_irq(b+30, fec_enet_interrupt, 0, "fec(LC)", dev) != 0) - printk("FEC: Could not allocate FEC(LC) IRQ(%d+30)!\n", b); - if (request_irq(b+31, fec_enet_interrupt, 0, "fec(HBERR)", dev) != 0) - printk("FEC: Could not allocate FEC(HBERR) IRQ(%d+31)!\n", b); - if (request_irq(b+32, fec_enet_interrupt, 0, "fec(GRA)", dev) != 0) - printk("FEC: Could not allocate FEC(GRA) IRQ(%d+32)!\n", b); - if (request_irq(b+33, fec_enet_interrupt, 0, "fec(EBERR)", dev) != 0) - printk("FEC: Could not allocate FEC(EBERR) IRQ(%d+33)!\n", b); - if (request_irq(b+34, fec_enet_interrupt, 0, "fec(BABT)", dev) != 0) - printk("FEC: Could not allocate FEC(BABT) IRQ(%d+34)!\n", b); - if (request_irq(b+35, fec_enet_interrupt, 0, "fec(BABR)", dev) != 0) - printk("FEC: Could not allocate FEC(BABR) IRQ(%d+35)!\n", b); + for (idp = id; idp->name; idp++) { + if (request_irq(b+idp->irq, fec_enet_interrupt, 0, idp->name, dev) != 0) + printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); + } /* Unmask interrupts at ColdFire 5280/5282 interrupt controller */ { @@ -1300,11 +1335,13 @@ static void __inline__ fec_request_intrs(struct net_device *dev) #if defined(CONFIG_M528x) /* Set up gpio outputs for MII lines */ { - volatile unsigned short *gpio_paspar; + volatile u16 *gpio_paspar; + volatile u8 *gpio_pehlpar; - gpio_paspar = (volatile unsigned short *) (MCF_IPSBAR + - 0x100056); - *gpio_paspar = 0x0f00; + gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056); + gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058); + *gpio_paspar |= 0x0f00; + *gpio_pehlpar = 0xc0; } #endif } @@ -1331,17 +1368,16 @@ static void __inline__ fec_get_mac(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile fec_t *fecp; - unsigned char *iap, tmpaddr[6]; - int i; + unsigned char *iap, tmpaddr[ETH_ALEN]; fecp = fep->hwp; - if (fec_flashmac) { + if (FEC_FLASHMAC) { /* * Get MAC address from FLASH. * If it is all 1's or 0's, use the default. */ - iap = fec_flashmac; + iap = FEC_FLASHMAC; if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) iap = fec_mac_default; @@ -1354,14 +1390,11 @@ static void __inline__ fec_get_mac(struct net_device *dev) iap = &tmpaddr[0]; } - for (i=0; i<ETH_ALEN; i++) - dev->dev_addr[i] = fep->mac_addr[i] = *iap++; + memcpy(dev->dev_addr, iap, ETH_ALEN); /* Adjust MAC if using default MAC address */ - if (iap == fec_mac_default) { - dev->dev_addr[ETH_ALEN-1] = fep->mac_addr[ETH_ALEN-1] = - iap[ETH_ALEN-1] + fep->index; - } + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; } static void __inline__ fec_enable_phy_intr(void) @@ -1392,7 +1425,7 @@ static void __inline__ fec_uncache(unsigned long addr) #else /* - * Code sepcific to the MPC860T setup. + * Code specific to the MPC860T setup. */ static void __inline__ fec_request_intrs(struct net_device *dev) { @@ -1424,13 +1457,10 @@ static void __inline__ fec_request_intrs(struct net_device *dev) static void __inline__ fec_get_mac(struct net_device *dev) { - struct fec_enet_private *fep = netdev_priv(dev); - unsigned char *iap, tmpaddr[6]; bd_t *bd; - int i; - iap = bd->bi_enetaddr; bd = (bd_t *)__res; + memcpy(dev->dev_addr, bd->bi_enetaddr, ETH_ALEN); #ifdef CONFIG_RPXCLASSIC /* The Embedded Planet boards have only one MAC address in @@ -1439,14 +1469,8 @@ static void __inline__ fec_get_mac(struct net_device *dev) * the address bits above something that would have (up to * now) been allocated. */ - for (i=0; i<6; i++) - tmpaddr[i] = *iap++; - tmpaddr[3] |= 0x80; - iap = tmpaddr; + dev->dev_adrd[3] |= 0x80; #endif - - for (i=0; i<6; i++) - dev->dev_addr[i] = fep->mac_addr[i] = *iap++; } static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) @@ -1556,7 +1580,7 @@ static void mii_display_status(struct net_device *dev) static void mii_display_config(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); + uint status = fep->phy_status; /* ** When we get here, phy_task is already removed from @@ -1565,23 +1589,23 @@ static void mii_display_config(struct net_device *dev) fep->mii_phy_task_queued = 0; printk("%s: config: auto-negotiation ", dev->name); - if (*s & PHY_CONF_ANE) + if (status & PHY_CONF_ANE) printk("on"); else printk("off"); - if (*s & PHY_CONF_100FDX) + if (status & PHY_CONF_100FDX) printk(", 100FDX"); - if (*s & PHY_CONF_100HDX) + if (status & PHY_CONF_100HDX) printk(", 100HDX"); - if (*s & PHY_CONF_10FDX) + if (status & PHY_CONF_10FDX) printk(", 10FDX"); - if (*s & PHY_CONF_10HDX) + if (status & PHY_CONF_10HDX) printk(", 10HDX"); - if (!(*s & PHY_CONF_SPMASK)) + if (!(status & PHY_CONF_SPMASK)) printk(", No speed/duplex selected?"); - if (*s & PHY_CONF_LOOP) + if (status & PHY_CONF_LOOP) printk(", loopback enabled"); printk(".\n"); @@ -1639,7 +1663,7 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev) schedule_work(&fep->phy_task); } -/* mii_queue_config is called in user context from fec_enet_open */ +/* mii_queue_config is called in interrupt context from fec_enet_mii */ static void mii_queue_config(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); @@ -1652,14 +1676,14 @@ static void mii_queue_config(uint mii_reg, struct net_device *dev) schedule_work(&fep->phy_task); } - - -phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_REG_CR), mii_queue_relink }, - { mk_mii_end, } }; -phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config }, - { mk_mii_end, } }; - - +phy_cmd_t const phy_cmd_relink[] = { + { mk_mii_read(MII_REG_CR), mii_queue_relink }, + { mk_mii_end, } + }; +phy_cmd_t const phy_cmd_config[] = { + { mk_mii_read(MII_REG_CR), mii_queue_config }, + { mk_mii_end, } + }; /* Read remainder of PHY ID. */ @@ -1897,17 +1921,15 @@ static void set_multicast_list(struct net_device *dev) static void fec_set_mac_address(struct net_device *dev) { - struct fec_enet_private *fep; volatile fec_t *fecp; - fep = netdev_priv(dev); - fecp = fep->hwp; + fecp = ((struct fec_enet_private *)netdev_priv(dev))->hwp; /* Set station address. */ - fecp->fec_addr_low = fep->mac_addr[3] | (fep->mac_addr[2] << 8) | - (fep->mac_addr[1] << 16) | (fep->mac_addr[0] << 24); - fecp->fec_addr_high = (fep->mac_addr[5] << 16) | - (fep->mac_addr[4] << 24); + fecp->fec_addr_low = dev->dev_addr[3] | (dev->dev_addr[2] << 8) | + (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24); + fecp->fec_addr_high = (dev->dev_addr[5] << 16) | + (dev->dev_addr[4] << 24); } @@ -1943,7 +1965,7 @@ int __init fec_enet_init(struct net_device *dev) udelay(10); /* Clear and enable interrupts */ - fecp->fec_ievent = 0xffc0; + fecp->fec_ievent = 0xffc00000; fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); fecp->fec_hash_table_high = 0; @@ -2063,11 +2085,6 @@ int __init fec_enet_init(struct net_device *dev) /* setup MII interface */ fec_set_mii(dev, fep); - printk("%s: FEC ENET Version 0.2, ", dev->name); - for (i=0; i<5; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x\n", dev->dev_addr[5]); - /* Queue up command to detect the PHY and initialize the * remainder of the interface. */ @@ -2106,18 +2123,12 @@ fec_restart(struct net_device *dev, int duplex) /* Clear any outstanding interrupt. */ - fecp->fec_ievent = 0xffc0; + fecp->fec_ievent = 0xffc00000; fec_enable_phy_intr(); /* Set station address. */ - fecp->fec_addr_low = fep->mac_addr[3] | (fep->mac_addr[2] << 8) | - (fep->mac_addr[1] << 16) | (fep->mac_addr[0] << 24); - fecp->fec_addr_high = (fep->mac_addr[5] << 16) | - (fep->mac_addr[4] << 24); - - for (i=0; i<ETH_ALEN; i++) - dev->dev_addr[i] = fep->mac_addr[i]; + fec_set_mac_address(dev); /* Reset all multicast. */ @@ -2215,7 +2226,7 @@ fec_stop(struct net_device *dev) fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ - while(!(fecp->fec_ievent & 0x10000000)); + while(!(fecp->fec_ievent & FEC_ENET_GRA)); /* Whack a reset. We should wait for this. */ @@ -2234,7 +2245,9 @@ fec_stop(struct net_device *dev) static int __init fec_enet_module_init(void) { struct net_device *dev; - int i, err; + int i, j, err; + + printk("FEC ENET Version 0.2\n"); for (i = 0; (i < FEC_MAX_PORTS); i++) { dev = alloc_etherdev(sizeof(struct fec_enet_private)); @@ -2250,6 +2263,11 @@ static int __init fec_enet_module_init(void) free_netdev(dev); return -EIO; } + + printk("%s: ethernet ", dev->name); + for (j = 0; (j < 5); j++) + printk("%02x:", dev->dev_addr[j]); + printk("%02x\n", dev->dev_addr[5]); } return 0; } -- GitLab From 8a6e43e9ee84eb8fb39bfdf8f0b6e466905491d0 Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 461/563] [PATCH] m68knommu: cache support for 523x/528x processors Add support for the cache of the ColdFIre 523x family of processors. Enable the 528x cache by default now, all final shipping silicon has the cache bug fixed. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-m68knommu/mcfcache.h | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/include/asm-m68knommu/mcfcache.h b/include/asm-m68knommu/mcfcache.h index bdd8c53ef34ce..b17cd920977f5 100644 --- a/include/asm-m68knommu/mcfcache.h +++ b/include/asm-m68knommu/mcfcache.h @@ -33,7 +33,7 @@ .endm #endif /* CONFIG_M5206 || CONFIG_M5206e || CONFIG_M5272 */ -#if defined(CONFIG_M527x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) /* * New version 2 cores have a configurable split cache arrangement. * For now I am just enabling instruction cache - but ultimately I @@ -51,23 +51,20 @@ movec %d0,%CACR /* enable cache */ nop .endm -#endif /* CONFIG_M527x */ +#endif /* CONFIG_M523x || CONFIG_M527x */ #if defined(CONFIG_M528x) -/* - * Cache is totally broken on early 5282 silicon. So far now we - * disable its cache all together. - */ .macro CACHE_ENABLE - movel #0x01000000,%d0 - movec %d0,%CACR /* invalidate cache */ nop - movel #0x0000c000,%d0 /* set SDRAM cached only */ - movec %d0,%ACR0 - movel #0x00000000,%d0 /* no other regions cached */ - movec %d0,%ACR1 - movel #0x00000000,%d0 /* configure cache */ - movec %d0,%CACR /* enable cache */ + movel #0x01000000, %d0 + movec %d0, %CACR /* Invalidate cache */ + nop + movel #0x0000c020, %d0 /* Set SDRAM cached only */ + movec %d0, %ACR0 + movel #0xff00c000, %d0 /* Cache Flash also */ + movec %d0, %ACR1 + movel #0x80000200, %d0 /* Setup cache mask */ + movec %d0, %CACR /* Enable cache */ nop .endm #endif /* CONFIG_M528x */ -- GitLab From 42ae766fffdad89267151acddaf936df58ab2267 Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 462/563] [PATCH] m68knommu: common ROM/flash based 68360 startup code Create common start code for all 68360 based platforms that are loaded and run directly from ROM/flash (as opposed to running from RAM). This replaces the old specific startup code for each board. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/m68knommu/platform/68360/head-rom.S | 420 +++++++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 arch/m68knommu/platform/68360/head-rom.S diff --git a/arch/m68knommu/platform/68360/head-rom.S b/arch/m68knommu/platform/68360/head-rom.S new file mode 100644 index 0000000000000..0da357a4cfee4 --- /dev/null +++ b/arch/m68knommu/platform/68360/head-rom.S @@ -0,0 +1,420 @@ +/* arch/m68knommu/platform/68360/head-rom.S + * + * Startup code for Motorola 68360 + * + * Copyright (C) SED Systems, a Division of Calian Ltd. + * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S + * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7 + * uClinux Kernel + * Copyright (C) Michael Leslie <mleslie@lineo.com> + * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S + * Copyright (C) 1998 D. Jeff Dionne <jeff@uclinux.org>, + * + */ +#include <linux/config.h> + +.global _stext +.global _sbss +.global _start + +.global _rambase +.global __ramvec +.global _ramvec +.global _ramstart +.global _ramend + +.global _quicc_base +.global _periph_base + +#define REGB 0x1000 +#define PEPAR (_dprbase + REGB + 0x0016) +#define GMR (_dprbase + REGB + 0x0040) +#define OR0 (_dprbase + REGB + 0x0054) +#define BR0 (_dprbase + REGB + 0x0050) + +#define OR1 (_dprbase + REGB + 0x0064) +#define BR1 (_dprbase + REGB + 0x0060) + +#define OR2 (_dprbase + REGB + 0x0074) +#define BR2 (_dprbase + REGB + 0x0070) + +#define OR3 (_dprbase + REGB + 0x0084) +#define BR3 (_dprbase + REGB + 0x0080) + +#define OR4 (_dprbase + REGB + 0x0094) +#define BR4 (_dprbase + REGB + 0x0090) + +#define OR5 (_dprbase + REGB + 0x00A4) +#define BR5 (_dprbase + REGB + 0x00A0) + +#define OR6 (_dprbase + REGB + 0x00b4) +#define BR6 (_dprbase + REGB + 0x00b0) + +#define OR7 (_dprbase + REGB + 0x00c4) +#define BR7 (_dprbase + REGB + 0x00c0) + +#define MCR (_dprbase + REGB + 0x0000) +#define AVR (_dprbase + REGB + 0x0008) + +#define SYPCR (_dprbase + REGB + 0x0022) + +#define PLLCR (_dprbase + REGB + 0x0010) +#define CLKOCR (_dprbase + REGB + 0x000C) +#define CDVCR (_dprbase + REGB + 0x0014) + +#define BKAR (_dprbase + REGB + 0x0030) +#define BKCR (_dprbase + REGB + 0x0034) +#define SWIV (_dprbase + REGB + 0x0023) +#define PICR (_dprbase + REGB + 0x0026) +#define PITR (_dprbase + REGB + 0x002A) + +/* Define for all memory configuration */ +#define MCU_SIM_GMR 0x00000000 +#define SIM_OR_MASK 0x0fffffff + +/* Defines for chip select zero - the flash */ +#define SIM_OR0_MASK 0x20000000 +#define SIM_BR0_MASK 0x00000001 + +/* Defines for chip select one - the RAM */ +#define SIM_OR1_MASK 0x10000000 +#define SIM_BR1_MASK 0x00000001 + +#define MCU_SIM_MBAR_ADRS 0x0003ff00 +#define MCU_SIM_MBAR_BA_MASK 0xfffff000 +#define MCU_SIM_MBAR_AS_MASK 0x00000001 + +#define MCU_SIM_PEPAR 0x00B4 + +#define MCU_DISABLE_INTRPTS 0x2700 +#define MCU_SIM_AVR 0x00 + +#define MCU_SIM_MCR 0x00005cff + +#define MCU_SIM_CLKOCR 0x00 +#define MCU_SIM_PLLCR 0x8000 +#define MCU_SIM_CDVCR 0x0000 + +#define MCU_SIM_SYPCR 0x0000 +#define MCU_SIM_SWIV 0x00 +#define MCU_SIM_PICR 0x0000 +#define MCU_SIM_PITR 0x0000 + + +#include <asm/m68360_regs.h> + + +/* + * By the time this RAM specific code begins to execute, DPRAM + * and DRAM should already be mapped and accessible. + */ + + .text +_start: +_stext: + nop + ori.w #MCU_DISABLE_INTRPTS, %sr /* disable interrupts: */ + /* We should not need to setup the boot stack the reset should do it. */ + movea.l #__ramend, %sp /* set up stack at the end of DRAM:*/ + + +set_mbar_register: + moveq.l #0x07, %d1 /* Setup MBAR */ + movec %d1, %dfc + + lea.l MCU_SIM_MBAR_ADRS, %a0 + move.l #_dprbase, %d0 + andi.l #MCU_SIM_MBAR_BA_MASK, %d0 + ori.l #MCU_SIM_MBAR_AS_MASK, %d0 + moves.l %d0, %a0@ + + moveq.l #0x05, %d1 + movec.l %d1, %dfc + + /* Now we can begin to access registers in DPRAM */ + +set_sim_mcr: + /* Set Module Configuration Register */ + move.l #MCU_SIM_MCR, MCR + + /* to do: Determine cause of reset */ + + /* + * configure system clock MC68360 p. 6-40 + * (value +1)*osc/128 = system clock + * or + * (value + 1)*osc = system clock + * You do not need to divide the oscillator by 128 unless you want to. + */ +set_sim_clock: + move.w #MCU_SIM_PLLCR, PLLCR + move.b #MCU_SIM_CLKOCR, CLKOCR + move.w #MCU_SIM_CDVCR, CDVCR + + /* Wait for the PLL to settle */ + move.w #16384, %d0 +pll_settle_wait: + subi.w #1, %d0 + bne pll_settle_wait + + /* Setup the system protection register, and watchdog timer register */ + move.b #MCU_SIM_SWIV, SWIV + move.w #MCU_SIM_PICR, PICR + move.w #MCU_SIM_PITR, PITR + move.w #MCU_SIM_SYPCR, SYPCR + + /* Clear DPRAM - system + parameter */ + movea.l #_dprbase, %a0 + movea.l #_dprbase+0x2000, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +clear_dpram: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi clear_dpram + +configure_memory_controller: + /* Set up Global Memory Register (GMR) */ + move.l #MCU_SIM_GMR, %d0 + move.l %d0, GMR + +configure_chip_select_0: + move.l #0x00400000, %d0 + subq.l #0x01, %d0 + eori.l #SIM_OR_MASK, %d0 + ori.l #SIM_OR0_MASK, %d0 + move.l %d0, OR0 + + move.l #__rom_start, %d0 + ori.l #SIM_BR0_MASK, %d0 + move.l %d0, BR0 + + move.l #0x0, BR1 + move.l #0x0, BR2 + move.l #0x0, BR3 + move.l #0x0, BR4 + move.l #0x0, BR5 + move.l #0x0, BR6 + move.l #0x0, BR7 + + move.w #MCU_SIM_PEPAR, PEPAR + + /* point to vector table: */ + move.l #_romvec, %a0 + move.l #_ramvec, %a1 +copy_vectors: + move.l %a0@, %d0 + move.l %d0, %a1@ + move.l %a0@, %a1@ + addq.l #0x04, %a0 + addq.l #0x04, %a1 + cmp.l #_start, %a0 + blt copy_vectors + + move.l #_ramvec, %a1 + movec %a1, %vbr + + + /* Copy data segment from ROM to RAM */ + moveal #_etext, %a0 + moveal #_sdata, %a1 + moveal #_edata, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +LD1: + move.l %a0@, %d0 + addq.l #0x04, %a0 + move.l %d0, %a1@ + addq.l #0x04, %a1 + cmp.l #_edata, %a1 + blt LD1 + + moveal #_sbss, %a0 + moveal #_ebss, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +L1: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi L1 + +load_quicc: + move.l #_dprbase, _quicc_base + +store_ram_size: + /* Set ram size information */ + move.l #_sdata, _rambase + move.l #_ebss, _ramstart + move.l #__ramend, %d0 + sub.l #0x1000, %d0 /* Reserve 4K for stack space.*/ + move.l %d0, _ramend /* Different from __ramend.*/ + +store_flash_size: + /* Set rom size information */ + move.l #__rom_end, %d0 + sub.l #__rom_start, %d0 + move.l %d0, rom_length + + pea 0 + pea env + pea %sp@(4) + pea 0 + + lea init_thread_union, %a2 + lea 0x2000(%a2), %sp + +lp: + jsr start_kernel + +_exit: + jmp _exit + + + .data + .align 4 +env: + .long 0 +_quicc_base: + .long 0 +_periph_base: + .long 0 +_ramvec: + .long 0 +_rambase: + .long 0 +_ramstart: + .long 0 +_ramend: + .long 0 +_dprbase: + .long 0xffffe000 + + + .text + + /* + * These are the exception vectors at boot up, they are copied into RAM + * and then overwritten as needed. + */ + +.section ".data.initvect","awx" + .long __ramend /* Reset: Initial Stack Pointer - 0. */ + .long _start /* Reset: Initial Program Counter - 1. */ + .long buserr /* Bus Error - 2. */ + .long trap /* Address Error - 3. */ + .long trap /* Illegal Instruction - 4. */ + .long trap /* Divide by zero - 5. */ + .long trap /* CHK, CHK2 Instructions - 6. */ + .long trap /* TRAPcc, TRAPV Instructions - 7. */ + .long trap /* Privilege Violation - 8. */ + .long trap /* Trace - 9. */ + .long trap /* Line 1010 Emulator - 10. */ + .long trap /* Line 1111 Emualtor - 11. */ + .long trap /* Harware Breakpoint - 12. */ + .long trap /* (Reserved for Coprocessor Protocol Violation)- 13. */ + .long trap /* Format Error - 14. */ + .long trap /* Uninitialized Interrupt - 15. */ + .long trap /* (Unassigned, Reserver) - 16. */ + .long trap /* (Unassigned, Reserver) - 17. */ + .long trap /* (Unassigned, Reserver) - 18. */ + .long trap /* (Unassigned, Reserver) - 19. */ + .long trap /* (Unassigned, Reserver) - 20. */ + .long trap /* (Unassigned, Reserver) - 21. */ + .long trap /* (Unassigned, Reserver) - 22. */ + .long trap /* (Unassigned, Reserver) - 23. */ + .long trap /* Spurious Interrupt - 24. */ + .long trap /* Level 1 Interrupt Autovector - 25. */ + .long trap /* Level 2 Interrupt Autovector - 26. */ + .long trap /* Level 3 Interrupt Autovector - 27. */ + .long trap /* Level 4 Interrupt Autovector - 28. */ + .long trap /* Level 5 Interrupt Autovector - 29. */ + .long trap /* Level 6 Interrupt Autovector - 30. */ + .long trap /* Level 7 Interrupt Autovector - 31. */ + .long system_call /* Trap Instruction Vectors 0 - 32. */ + .long trap /* Trap Instruction Vectors 1 - 33. */ + .long trap /* Trap Instruction Vectors 2 - 34. */ + .long trap /* Trap Instruction Vectors 3 - 35. */ + .long trap /* Trap Instruction Vectors 4 - 36. */ + .long trap /* Trap Instruction Vectors 5 - 37. */ + .long trap /* Trap Instruction Vectors 6 - 38. */ + .long trap /* Trap Instruction Vectors 7 - 39. */ + .long trap /* Trap Instruction Vectors 8 - 40. */ + .long trap /* Trap Instruction Vectors 9 - 41. */ + .long trap /* Trap Instruction Vectors 10 - 42. */ + .long trap /* Trap Instruction Vectors 11 - 43. */ + .long trap /* Trap Instruction Vectors 12 - 44. */ + .long trap /* Trap Instruction Vectors 13 - 45. */ + .long trap /* Trap Instruction Vectors 14 - 46. */ + .long trap /* Trap Instruction Vectors 15 - 47. */ + .long 0 /* (Reserved for Coprocessor) - 48. */ + .long 0 /* (Reserved for Coprocessor) - 49. */ + .long 0 /* (Reserved for Coprocessor) - 50. */ + .long 0 /* (Reserved for Coprocessor) - 51. */ + .long 0 /* (Reserved for Coprocessor) - 52. */ + .long 0 /* (Reserved for Coprocessor) - 53. */ + .long 0 /* (Reserved for Coprocessor) - 54. */ + .long 0 /* (Reserved for Coprocessor) - 55. */ + .long 0 /* (Reserved for Coprocessor) - 56. */ + .long 0 /* (Reserved for Coprocessor) - 57. */ + .long 0 /* (Reserved for Coprocessor) - 58. */ + .long 0 /* (Unassigned, Reserved) - 59. */ + .long 0 /* (Unassigned, Reserved) - 60. */ + .long 0 /* (Unassigned, Reserved) - 61. */ + .long 0 /* (Unassigned, Reserved) - 62. */ + .long 0 /* (Unassigned, Reserved) - 63. */ + /* The assignment of these vectors to the CPM is */ + /* dependent on the configuration of the CPM vba */ + /* fields. */ + .long 0 /* (User-Defined Vectors 1) CPM Error - 64. */ + .long 0 /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */ + .long 0 /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */ + .long 0 /* (User-Defined Vectors 4) CPM SMC2 / PIP - 67. */ + .long 0 /* (User-Defined Vectors 5) CPM SMC1 - 68. */ + .long 0 /* (User-Defined Vectors 6) CPM SPI - 69. */ + .long 0 /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */ + .long 0 /* (User-Defined Vectors 8) CPM Timer 4 - 71. */ + .long 0 /* (User-Defined Vectors 9) CPM Reserved - 72. */ + .long 0 /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */ + .long 0 /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */ + .long 0 /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */ + .long 0 /* (User-Defined Vectors 13) CPM Timer 3 - 76. */ + .long 0 /* (User-Defined Vectors 14) CPM Reserved - 77. */ + .long 0 /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */ + .long 0 /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */ + .long 0 /* (User-Defined Vectors 17) CPM Reserved - 80. */ + .long 0 /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */ + .long 0 /* (User-Defined Vectors 19) CPM Timer 2 - 82. */ + .long 0 /* (User-Defined Vectors 21) CPM Reserved - 83. */ + .long 0 /* (User-Defined Vectors 22) CPM IDMA2 - 84. */ + .long 0 /* (User-Defined Vectors 23) CPM IDMA1 - 85. */ + .long 0 /* (User-Defined Vectors 24) CPM SDMA Bus Err - 86. */ + .long 0 /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */ + .long 0 /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */ + .long 0 /* (User-Defined Vectors 27) CPM Timer 1 - 89. */ + .long 0 /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */ + .long 0 /* (User-Defined Vectors 29) CPM SCC 4 - 91. */ + .long 0 /* (User-Defined Vectors 30) CPM SCC 3 - 92. */ + .long 0 /* (User-Defined Vectors 31) CPM SCC 2 - 93. */ + .long 0 /* (User-Defined Vectors 32) CPM SCC 1 - 94. */ + .long 0 /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */ + /* I don't think anything uses the vectors after here. */ + .long 0 /* (User-Defined Vectors 34) - 96. */ + .long 0,0,0,0,0 /* (User-Defined Vectors 35 - 39). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 40 - 49). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 50 - 59). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 60 - 69). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 70 - 79). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 80 - 89). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 90 - 99). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 100 - 109). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 110 - 119). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 120 - 129). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 130 - 139). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 140 - 149). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 150 - 159). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 160 - 169). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 170 - 179). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 180 - 189). */ + .long 0,0,0 /* (User-Defined Vectors 190 - 192). */ +.text +ignore: rte -- GitLab From df28f34bf998795c4d4e08c1604eac0a6d84f502 Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 463/563] [PATCH] m68knommu: correct prototype args in checksum.h Bring arg types for csum_partial_copy and csum_paritial_copy_from_user prototypes into line with their actual implementation. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-m68knommu/checksum.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/asm-m68knommu/checksum.h b/include/asm-m68knommu/checksum.h index 92cf102c2534c..294ec7583ac91 100644 --- a/include/asm-m68knommu/checksum.h +++ b/include/asm-m68knommu/checksum.h @@ -25,7 +25,8 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) * better 64-bit) boundary */ -unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); +unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst, + int len, int sum); /* @@ -35,8 +36,8 @@ unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); * better 64-bit) boundary */ -extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, - int len, int sum, int *csum_err); +extern unsigned int csum_partial_copy_from_user(const unsigned char *src, + unsigned char *dst, int len, int sum, int *csum_err); #define csum_partial_copy_nocheck(src, dst, len, sum) \ csum_partial_copy((src), (dst), (len), (sum)) -- GitLab From 9c1ee9387c0ce06d573e2d27de10cbc24179941e Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 464/563] [PATCH] m68knommu: change addr arg to const in bitops.h/find_next_zero_bit() Change addr arg to find_next_zero_bit to be a const. Cleans up compiler warning. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-m68knommu/bitops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-m68knommu/bitops.h b/include/asm-m68knommu/bitops.h index f95e32b404254..c42f88a9b9f98 100644 --- a/include/asm-m68knommu/bitops.h +++ b/include/asm-m68knommu/bitops.h @@ -259,7 +259,7 @@ static __inline__ int __test_bit(int nr, const volatile unsigned long * addr) #define find_first_bit(addr, size) \ find_next_bit((addr), (size), 0) -static __inline__ int find_next_zero_bit (void * addr, int size, int offset) +static __inline__ int find_next_zero_bit (const void * addr, int size, int offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; -- GitLab From b0433b99339a9fdc2effe213491812556e4896fb Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 465/563] [PATCH] m68knommu: add ColdFire serial driver support for 523x processor family Add support for the new Freescale 523x processor family to ColdFire serial driver. Also set different default baud rate for MOD5272 board. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/serial/mcfserial.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 43b03c55f4538..e2ebdcad553c4 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -63,8 +63,13 @@ struct timer_list mcfrs_timer_struct; #endif #if defined(CONFIG_HW_FEITH) - #define CONSOLE_BAUD_RATE 38400 - #define DEFAULT_CBAUD B38400 +#define CONSOLE_BAUD_RATE 38400 +#define DEFAULT_CBAUD B38400 +#endif + +#if defined(CONFIG_MOD5272) +#define CONSOLE_BAUD_RATE 115200 +#define DEFAULT_CBAUD B115200 #endif #ifndef CONSOLE_BAUD_RATE @@ -90,7 +95,7 @@ static struct tty_driver *mcfrs_serial_driver; #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_FLOW -#if defined(CONFIG_M527x) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) #define IRQBASE (MCFINT_VECBASE+MCFINT_UART0) #else #define IRQBASE 73 @@ -1510,7 +1515,7 @@ static void mcfrs_irqinit(struct mcf_serial *info) *portp = (*portp & ~0x000000ff) | 0x00000055; portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT); *portp = (*portp & ~0x000003fc) | 0x000002a8; -#elif defined(CONFIG_M527x) || defined(CONFIG_M528x) +#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) volatile unsigned char *icrp, *uartp; volatile unsigned long *imrp; -- GitLab From f6515db47e6d8cb502e4b0fd7255652da4ba1393 Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 466/563] [PATCH] uclinux: remove use of mtd_put_device() in uclinux MTD map driver We should not call mtd_put_device() in the uclinux MTD map driver. Also consistently use phys/virt fields of maps map_info struct, instead of mixing it with map_priv_1. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/mtd/maps/uclinux.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 811d92e5f5b14..cc372136e8527 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -23,9 +23,6 @@ #include <linux/mtd/partitions.h> #include <asm/io.h> -/****************************************************************************/ - - /****************************************************************************/ struct map_info uclinux_ram_map = { @@ -60,14 +57,15 @@ int __init uclinux_mtd_init(void) struct mtd_info *mtd; struct map_info *mapp; extern char _ebss; + unsigned long addr = (unsigned long) &_ebss; mapp = &uclinux_ram_map; - mapp->phys = (unsigned long) &_ebss; - mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8))); + mapp->phys = addr; + mapp->size = PAGE_ALIGN(ntohl(*((unsigned long *)(addr + 8)))); mapp->bankwidth = 4; printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n", - (int) mapp->map_priv_2, (int) mapp->size); + (int) mapp->phys, (int) mapp->size); mapp->virt = ioremap_nocache(mapp->phys, mapp->size); @@ -95,7 +93,6 @@ int __init uclinux_mtd_init(void) printk("uclinux[mtd]: set %s to be root filesystem\n", uclinux_romfs[0].name); ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 0); - put_mtd_device(mtd); return(0); } @@ -109,7 +106,7 @@ void __exit uclinux_mtd_cleanup(void) map_destroy(uclinux_ram_mtdinfo); uclinux_ram_mtdinfo = NULL; } - if (uclinux_ram_map.map_priv_1) { + if (uclinux_ram_map.virt) { iounmap((void *) uclinux_ram_map.virt); uclinux_ram_map.virt = 0; } -- GitLab From 966cdb2fdf1776392c98f7d38e0eb9c6dd1c4715 Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 467/563] [PATCH] m68knommu: dma support for 523x processors Support the DMA unit of the ColdFire 523x processor family. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-m68knommu/mcfdma.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-m68knommu/mcfdma.h b/include/asm-m68knommu/mcfdma.h index 350c6090b5c1e..b93f8ba8a248e 100644 --- a/include/asm-m68knommu/mcfdma.h +++ b/include/asm-m68knommu/mcfdma.h @@ -21,7 +21,7 @@ #define MCFDMA_BASE1 0x240 /* Base address of DMA 1 */ #elif defined(CONFIG_M5272) #define MCFDMA_BASE0 0x0e0 /* Base address of DMA 0 */ -#elif defined(CONFIG_M527x) || defined(CONFIG_M528x) +#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) /* These are relative to the IPSBAR, not MBAR */ #define MCFDMA_BASE0 0x100 /* Base address of DMA 0 */ #define MCFDMA_BASE1 0x140 /* Base address of DMA 1 */ -- GitLab From 66aa2b4b1cf9a61f1550251c56fc6f0d48287591 Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 468/563] [PATCH] uclinux: add NULL check, 0 end valid check and some more exports to nommu.c Move call to get_mm_counter() in update_mem_hiwater() to be inside the check for tsk->mm being null. Otherwise you can be following a null pointer here. This patch submitted by Javier Herrero <jherrero@hvsistemas.es>. Modify the end check for munmap regions to allow for the legacy behavior of 0 being valid. Pretty much all current uClinux system libc malloc's pass in 0 as the end point. A hard check will fail on these, so change the check so that if it is non-zero it must be valid otherwise it fails. A passed in value will always succeed (as it used too). Also export a few more mm system functions - to be consistent with the VM code exports. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- mm/nommu.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/mm/nommu.c b/mm/nommu.c index fd4e8df0f02df..064d70442895a 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -57,6 +57,11 @@ DECLARE_RWSEM(nommu_vma_sem); struct vm_operations_struct generic_file_vm_ops = { }; +EXPORT_SYMBOL(vmalloc); +EXPORT_SYMBOL(vfree); +EXPORT_SYMBOL(vmalloc_to_page); +EXPORT_SYMBOL(vmalloc_32); + /* * Handle all mappings that got truncated by a "truncate()" * system call. @@ -142,6 +147,8 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, return(i); } +EXPORT_SYMBOL(get_user_pages); + DEFINE_RWLOCK(vmlist_lock); struct vm_struct *vmlist; @@ -852,7 +859,7 @@ unsigned long do_mmap_pgoff(struct file *file, error_getting_vma: up_write(&nommu_vma_sem); kfree(vml); - printk("Allocation of vml for %lu byte allocation from process %d failed\n", + printk("Allocation of vma for %lu byte allocation from process %d failed\n", len, current->pid); show_free_areas(); return -ENOMEM; @@ -909,7 +916,7 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next) if ((*parent)->vma->vm_start == addr && - (*parent)->vma->vm_end == end) + ((len == 0) || ((*parent)->vma->vm_end == end))) goto found; printk("munmap of non-mmaped memory by process %d (%s): %p\n", @@ -1054,7 +1061,8 @@ struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr) int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_t prot) { - return -EPERM; + vma->vm_start = vma->vm_pgoff << PAGE_SHIFT; + return 0; } void swap_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) @@ -1073,9 +1081,10 @@ void arch_unmap_area(struct mm_struct *mm, unsigned long addr) void update_mem_hiwater(struct task_struct *tsk) { - unsigned long rss = get_mm_counter(tsk->mm, rss); + unsigned long rss; if (likely(tsk->mm)) { + rss = get_mm_counter(tsk->mm, rss); if (tsk->mm->hiwater_rss < rss) tsk->mm->hiwater_rss = rss; if (tsk->mm->hiwater_vm < tsk->mm->total_vm) -- GitLab From 7ce4d42503949b62f481be989d8f5a25f5af10ff Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 469/563] [PATCH] m68knommu: add SPI register definitions for 528x processors Add QSPI register definitions of ColdFIre 528x processor SPI controller. Patch originally submitted by Derek Cheung <derek.cheung@sympatico.ca> Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-m68knommu/m528xsim.h | 112 +++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/include/asm-m68knommu/m528xsim.h b/include/asm-m68knommu/m528xsim.h index 371993a206acd..610774a17f70d 100644 --- a/include/asm-m68knommu/m528xsim.h +++ b/include/asm-m68knommu/m528xsim.h @@ -41,5 +41,117 @@ #define MCFSIM_DACR1 0x50 /* SDRAM base address 1 */ #define MCFSIM_DMR1 0x54 /* SDRAM address mask 1 */ +/* + * Derek Cheung - 6 Feb 2005 + * add I2C and QSPI register definition using Freescale's MCF5282 + */ +/* set Port AS pin for I2C or UART */ +#define MCF5282_GPIO_PASPAR (volatile u16 *) (MCF_IPSBAR + 0x00100056) + +/* Interrupt Mask Register Register Low */ +#define MCF5282_INTC0_IMRL (volatile u32 *) (MCF_IPSBAR + 0x0C0C) +/* Interrupt Control Register 7 */ +#define MCF5282_INTC0_ICR17 (volatile u8 *) (MCF_IPSBAR + 0x0C51) + + + +/********************************************************************* +* +* Inter-IC (I2C) Module +* +*********************************************************************/ +/* Read/Write access macros for general use */ +#define MCF5282_I2C_I2ADR (volatile u8 *) (MCF_IPSBAR + 0x0300) // Address +#define MCF5282_I2C_I2FDR (volatile u8 *) (MCF_IPSBAR + 0x0304) // Freq Divider +#define MCF5282_I2C_I2CR (volatile u8 *) (MCF_IPSBAR + 0x0308) // Control +#define MCF5282_I2C_I2SR (volatile u8 *) (MCF_IPSBAR + 0x030C) // Status +#define MCF5282_I2C_I2DR (volatile u8 *) (MCF_IPSBAR + 0x0310) // Data I/O + +/* Bit level definitions and macros */ +#define MCF5282_I2C_I2ADR_ADDR(x) (((x)&0x7F)<<0x01) + +#define MCF5282_I2C_I2FDR_IC(x) (((x)&0x3F)) + +#define MCF5282_I2C_I2CR_IEN (0x80) // I2C enable +#define MCF5282_I2C_I2CR_IIEN (0x40) // interrupt enable +#define MCF5282_I2C_I2CR_MSTA (0x20) // master/slave mode +#define MCF5282_I2C_I2CR_MTX (0x10) // transmit/receive mode +#define MCF5282_I2C_I2CR_TXAK (0x08) // transmit acknowledge enable +#define MCF5282_I2C_I2CR_RSTA (0x04) // repeat start + +#define MCF5282_I2C_I2SR_ICF (0x80) // data transfer bit +#define MCF5282_I2C_I2SR_IAAS (0x40) // I2C addressed as a slave +#define MCF5282_I2C_I2SR_IBB (0x20) // I2C bus busy +#define MCF5282_I2C_I2SR_IAL (0x10) // aribitration lost +#define MCF5282_I2C_I2SR_SRW (0x04) // slave read/write +#define MCF5282_I2C_I2SR_IIF (0x02) // I2C interrupt +#define MCF5282_I2C_I2SR_RXAK (0x01) // received acknowledge + + + +/********************************************************************* +* +* Queued Serial Peripheral Interface (QSPI) Module +* +*********************************************************************/ +/* Derek - 21 Feb 2005 */ +/* change to the format used in I2C */ +/* Read/Write access macros for general use */ +#define MCF5282_QSPI_QMR MCF_IPSBAR + 0x0340 +#define MCF5282_QSPI_QDLYR MCF_IPSBAR + 0x0344 +#define MCF5282_QSPI_QWR MCF_IPSBAR + 0x0348 +#define MCF5282_QSPI_QIR MCF_IPSBAR + 0x034C +#define MCF5282_QSPI_QAR MCF_IPSBAR + 0x0350 +#define MCF5282_QSPI_QDR MCF_IPSBAR + 0x0354 +#define MCF5282_QSPI_QCR MCF_IPSBAR + 0x0354 + +/* Bit level definitions and macros */ +#define MCF5282_QSPI_QMR_MSTR (0x8000) +#define MCF5282_QSPI_QMR_DOHIE (0x4000) +#define MCF5282_QSPI_QMR_BITS_16 (0x0000) +#define MCF5282_QSPI_QMR_BITS_8 (0x2000) +#define MCF5282_QSPI_QMR_BITS_9 (0x2400) +#define MCF5282_QSPI_QMR_BITS_10 (0x2800) +#define MCF5282_QSPI_QMR_BITS_11 (0x2C00) +#define MCF5282_QSPI_QMR_BITS_12 (0x3000) +#define MCF5282_QSPI_QMR_BITS_13 (0x3400) +#define MCF5282_QSPI_QMR_BITS_14 (0x3800) +#define MCF5282_QSPI_QMR_BITS_15 (0x3C00) +#define MCF5282_QSPI_QMR_CPOL (0x0200) +#define MCF5282_QSPI_QMR_CPHA (0x0100) +#define MCF5282_QSPI_QMR_BAUD(x) (((x)&0x00FF)) + +#define MCF5282_QSPI_QDLYR_SPE (0x80) +#define MCF5282_QSPI_QDLYR_QCD(x) (((x)&0x007F)<<8) +#define MCF5282_QSPI_QDLYR_DTL(x) (((x)&0x00FF)) + +#define MCF5282_QSPI_QWR_HALT (0x8000) +#define MCF5282_QSPI_QWR_WREN (0x4000) +#define MCF5282_QSPI_QWR_WRTO (0x2000) +#define MCF5282_QSPI_QWR_CSIV (0x1000) +#define MCF5282_QSPI_QWR_ENDQP(x) (((x)&0x000F)<<8) +#define MCF5282_QSPI_QWR_CPTQP(x) (((x)&0x000F)<<4) +#define MCF5282_QSPI_QWR_NEWQP(x) (((x)&0x000F)) + +#define MCF5282_QSPI_QIR_WCEFB (0x8000) +#define MCF5282_QSPI_QIR_ABRTB (0x4000) +#define MCF5282_QSPI_QIR_ABRTL (0x1000) +#define MCF5282_QSPI_QIR_WCEFE (0x0800) +#define MCF5282_QSPI_QIR_ABRTE (0x0400) +#define MCF5282_QSPI_QIR_SPIFE (0x0100) +#define MCF5282_QSPI_QIR_WCEF (0x0008) +#define MCF5282_QSPI_QIR_ABRT (0x0004) +#define MCF5282_QSPI_QIR_SPIF (0x0001) + +#define MCF5282_QSPI_QAR_ADDR(x) (((x)&0x003F)) + +#define MCF5282_QSPI_QDR_COMMAND(x) (((x)&0xFF00)) +#define MCF5282_QSPI_QCR_DATA(x) (((x)&0x00FF)<<8) +#define MCF5282_QSPI_QCR_CONT (0x8000) +#define MCF5282_QSPI_QCR_BITSE (0x4000) +#define MCF5282_QSPI_QCR_DT (0x2000) +#define MCF5282_QSPI_QCR_DSCK (0x1000) +#define MCF5282_QSPI_QCR_CS (((x)&0x000F)<<8) + /****************************************************************************/ #endif /* m528xsim_h */ -- GitLab From 2d9d166e1cb2909bd8d3ac0d1ee8db83abb9fd86 Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 470/563] [PATCH] m68knommu: FEC eth definitions support for the 523x Coldfire processor family Add support for the FEC ethernet driver of the Freescale 523x processor family to the FEC header definitions. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/net/fec.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/fec.h b/drivers/net/fec.h index c6e4f979ff5d4..045761b8a6004 100644 --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -1,8 +1,9 @@ /****************************************************************************/ /* - * fec.h -- Fast Ethernet Controller for Motorola ColdFire 5270, - 5271, 5272, 5274, 5275, 5280 and 5282. + * fec.h -- Fast Ethernet Controller for Motorola ColdFire 5230, + * 5231, 5232, 5234, 5235, 5270, 5271, 5272, 5274, 5275, + * 5280 and 5282. * * (C) Copyright 2000-2003, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2000-2001, Lineo (www.lineo.com) @@ -13,7 +14,7 @@ #define FEC_H /****************************************************************************/ -#if defined(CONFIG_M527x) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) /* * Just figures, Motorola would have to change the offsets for * registers in the same peripheral device on different models -- GitLab From d871629b83774fc24db6dd2775ceaf46b433b056 Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 471/563] [PATCH] m68knommu: allow for SDRAM and GPIO differences on 5270/1 and 5274/5 processors Allow for differences in the SDRAM controller setup and GPIO pin setup of the 5270/1 and 5274/5 parts. With separate config options for each now this no longer needs to be board specific. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-m68knommu/m527xsim.h | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/include/asm-m68knommu/m527xsim.h b/include/asm-m68knommu/m527xsim.h index d280d013da032..e7878d0f7d7a5 100644 --- a/include/asm-m68knommu/m527xsim.h +++ b/include/asm-m68knommu/m527xsim.h @@ -37,13 +37,14 @@ /* * SDRAM configuration registers. */ -#ifdef CONFIG_M5271EVB +#ifdef CONFIG_M5271 #define MCFSIM_DCR 0x40 /* SDRAM control */ #define MCFSIM_DACR0 0x48 /* SDRAM base address 0 */ #define MCFSIM_DMR0 0x4c /* SDRAM address mask 0 */ #define MCFSIM_DACR1 0x50 /* SDRAM base address 1 */ #define MCFSIM_DMR1 0x54 /* SDRAM address mask 1 */ -#else +#endif +#ifdef CONFIG_M5275 #define MCFSIM_DMR 0x40 /* SDRAM mode */ #define MCFSIM_DCR 0x44 /* SDRAM control */ #define MCFSIM_DCFG1 0x48 /* SDRAM configuration 1 */ @@ -54,5 +55,21 @@ #define MCFSIM_DMR1 0x5c /* SDRAM address mask 1 */ #endif +/* + * GPIO pins setups to enable the UARTs. + */ +#ifdef CONFIG_M5271 +#define MCF_GPIO_PAR_UART 0x100048 /* PAR UART address */ +#define UART0_ENABLE_MASK 0x000f +#define UART1_ENABLE_MASK 0x0ff0 +#define UART2_ENABLE_MASK 0x3000 +#endif +#ifdef CONFIG_M5275 +#define MCF_GPIO_PAR_UART 0x10007c /* PAR UART address */ +#define UART0_ENABLE_MASK 0x000f +#define UART1_ENABLE_MASK 0x00f0 +#define UART2_ENABLE_MASK 0x3f00 +#endif + /****************************************************************************/ #endif /* m527xsim_h */ -- GitLab From 81d4903d2d17a9f33ece2666185a8b51e6935ae0 Mon Sep 17 00:00:00 2001 From: Greg Ungerer <gerg@snapgear.com> Date: Mon, 12 Sep 2005 11:18:10 +1000 Subject: [PATCH 472/563] [PATCH] m68knommu: common RAM based 68360 startup code Create common start code for all 68360 based platforms that are loaded and run directly from RAM (as opposed to running from flash/ROM). This replaces the old specific startup code for each board. Signed-off-by: Greg Ungerer <gerg@uclinux.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/m68knommu/platform/68360/head-ram.S | 408 +++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 arch/m68knommu/platform/68360/head-ram.S diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68knommu/platform/68360/head-ram.S new file mode 100644 index 0000000000000..a5c639a51eefd --- /dev/null +++ b/arch/m68knommu/platform/68360/head-ram.S @@ -0,0 +1,408 @@ +/* arch/m68knommu/platform/68360/head-ram.S + * + * Startup code for Motorola 68360 + * + * Copyright 2001 (C) SED Systems, a Division of Calian Ltd. + * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S + * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7 + * uClinux Kernel + * Copyright (C) Michael Leslie <mleslie@lineo.com> + * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S + * Copyright (C) 1998 D. Jeff Dionne <jeff@uclinux.org>, + * + */ +#define ASSEMBLY +#include <linux/config.h> + +.global _stext +.global _start + +.global _rambase +.global __ramvec +.global _ramvec +.global _ramstart +.global _ramend + +.global _quicc_base +.global _periph_base + +#define REGB 0x1000 +#define PEPAR (_dprbase + REGB + 0x0016) +#define GMR (_dprbase + REGB + 0x0040) +#define OR0 (_dprbase + REGB + 0x0054) +#define BR0 (_dprbase + REGB + 0x0050) +#define OR1 (_dprbase + REGB + 0x0064) +#define BR1 (_dprbase + REGB + 0x0060) +#define OR4 (_dprbase + REGB + 0x0094) +#define BR4 (_dprbase + REGB + 0x0090) +#define OR6 (_dprbase + REGB + 0x00b4) +#define BR6 (_dprbase + REGB + 0x00b0) +#define OR7 (_dprbase + REGB + 0x00c4) +#define BR7 (_dprbase + REGB + 0x00c0) + +#define MCR (_dprbase + REGB + 0x0000) +#define AVR (_dprbase + REGB + 0x0008) + +#define SYPCR (_dprbase + REGB + 0x0022) + +#define PLLCR (_dprbase + REGB + 0x0010) +#define CLKOCR (_dprbase + REGB + 0x000C) +#define CDVCR (_dprbase + REGB + 0x0014) + +#define BKAR (_dprbase + REGB + 0x0030) +#define BKCR (_dprbase + REGB + 0x0034) +#define SWIV (_dprbase + REGB + 0x0023) +#define PICR (_dprbase + REGB + 0x0026) +#define PITR (_dprbase + REGB + 0x002A) + +/* Define for all memory configuration */ +#define MCU_SIM_GMR 0x00000000 +#define SIM_OR_MASK 0x0fffffff + +/* Defines for chip select zero - the flash */ +#define SIM_OR0_MASK 0x20000002 +#define SIM_BR0_MASK 0x00000001 + + +/* Defines for chip select one - the RAM */ +#define SIM_OR1_MASK 0x10000000 +#define SIM_BR1_MASK 0x00000001 + +#define MCU_SIM_MBAR_ADRS 0x0003ff00 +#define MCU_SIM_MBAR_BA_MASK 0xfffff000 +#define MCU_SIM_MBAR_AS_MASK 0x00000001 + +#define MCU_SIM_PEPAR 0x00B4 + +#define MCU_DISABLE_INTRPTS 0x2700 +#define MCU_SIM_AVR 0x00 + +#define MCU_SIM_MCR 0x00005cff + +#define MCU_SIM_CLKOCR 0x00 +#define MCU_SIM_PLLCR 0x8000 +#define MCU_SIM_CDVCR 0x0000 + +#define MCU_SIM_SYPCR 0x0000 +#define MCU_SIM_SWIV 0x00 +#define MCU_SIM_PICR 0x0000 +#define MCU_SIM_PITR 0x0000 + + +#include <asm/m68360_regs.h> + + +/* + * By the time this RAM specific code begins to execute, DPRAM + * and DRAM should already be mapped and accessible. + */ + + .text +_start: +_stext: + nop + ori.w #MCU_DISABLE_INTRPTS, %sr /* disable interrupts: */ + /* We should not need to setup the boot stack the reset should do it. */ + movea.l #__ramend, %sp /*set up stack at the end of DRAM:*/ + +set_mbar_register: + moveq.l #0x07, %d1 /* Setup MBAR */ + movec %d1, %dfc + + lea.l MCU_SIM_MBAR_ADRS, %a0 + move.l #_dprbase, %d0 + andi.l #MCU_SIM_MBAR_BA_MASK, %d0 + ori.l #MCU_SIM_MBAR_AS_MASK, %d0 + moves.l %d0, %a0@ + + moveq.l #0x05, %d1 + movec.l %d1, %dfc + + /* Now we can begin to access registers in DPRAM */ + +set_sim_mcr: + /* Set Module Configuration Register */ + move.l #MCU_SIM_MCR, MCR + + /* to do: Determine cause of reset */ + + /* + * configure system clock MC68360 p. 6-40 + * (value +1)*osc/128 = system clock + */ +set_sim_clock: + move.w #MCU_SIM_PLLCR, PLLCR + move.b #MCU_SIM_CLKOCR, CLKOCR + move.w #MCU_SIM_CDVCR, CDVCR + + /* Wait for the PLL to settle */ + move.w #16384, %d0 +pll_settle_wait: + subi.w #1, %d0 + bne pll_settle_wait + + /* Setup the system protection register, and watchdog timer register */ + move.b #MCU_SIM_SWIV, SWIV + move.w #MCU_SIM_PICR, PICR + move.w #MCU_SIM_PITR, PITR + move.w #MCU_SIM_SYPCR, SYPCR + + /* Clear DPRAM - system + parameter */ + movea.l #_dprbase, %a0 + movea.l #_dprbase+0x2000, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +clear_dpram: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi clear_dpram + +configure_memory_controller: + /* Set up Global Memory Register (GMR) */ + move.l #MCU_SIM_GMR, %d0 + move.l %d0, GMR + +configure_chip_select_0: + move.l #__ramend, %d0 + subi.l #__ramstart, %d0 + subq.l #0x01, %d0 + eori.l #SIM_OR_MASK, %d0 + ori.l #SIM_OR0_MASK, %d0 + move.l %d0, OR0 + + move.l #__ramstart, %d0 + ori.l #SIM_BR0_MASK, %d0 + move.l %d0, BR0 + +configure_chip_select_1: + move.l #__rom_end, %d0 + subi.l #__rom_start, %d0 + subq.l #0x01, %d0 + eori.l #SIM_OR_MASK, %d0 + ori.l #SIM_OR1_MASK, %d0 + move.l %d0, OR1 + + move.l #__rom_start, %d0 + ori.l #SIM_BR1_MASK, %d0 + move.l %d0, BR1 + + move.w #MCU_SIM_PEPAR, PEPAR + + /* point to vector table: */ + move.l #_romvec, %a0 + move.l #_ramvec, %a1 +copy_vectors: + move.l %a0@, %d0 + move.l %d0, %a1@ + move.l %a0@, %a1@ + addq.l #0x04, %a0 + addq.l #0x04, %a1 + cmp.l #_start, %a0 + blt copy_vectors + + move.l #_ramvec, %a1 + movec %a1, %vbr + + + /* Copy data segment from ROM to RAM */ + moveal #_stext, %a0 + moveal #_sdata, %a1 + moveal #_edata, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +LD1: + move.l %a0@, %d0 + addq.l #0x04, %a0 + move.l %d0, %a1@ + addq.l #0x04, %a1 + cmp.l #_edata, %a1 + blt LD1 + + moveal #_sbss, %a0 + moveal #_ebss, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +L1: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi L1 + +load_quicc: + move.l #_dprbase, _quicc_base + +store_ram_size: + /* Set ram size information */ + move.l #_sdata, _rambase + move.l #_ebss, _ramstart + move.l #__ramend, %d0 + sub.l #0x1000, %d0 /* Reserve 4K for stack space.*/ + move.l %d0, _ramend /* Different from __ramend.*/ + +store_flash_size: + /* Set rom size information */ + move.l #__rom_end, %d0 + sub.l #__rom_start, %d0 + move.l %d0, rom_length + + pea 0 + pea env + pea %sp@(4) + pea 0 + + lea init_thread_union, %a2 + lea 0x2000(%a2), %sp + +lp: + jsr start_kernel + +_exit: + jmp _exit + + + .data + .align 4 +env: + .long 0 +_quicc_base: + .long 0 +_periph_base: + .long 0 +_ramvec: + .long 0 +_rambase: + .long 0 +_ramstart: + .long 0 +_ramend: + .long 0 +_dprbase: + .long 0xffffe000 + + .text + + /* + * These are the exception vectors at boot up, they are copied into RAM + * and then overwritten as needed. + */ + +.section ".data.initvect","awx" + .long __ramend /* Reset: Initial Stack Pointer - 0. */ + .long _start /* Reset: Initial Program Counter - 1. */ + .long buserr /* Bus Error - 2. */ + .long trap /* Address Error - 3. */ + .long trap /* Illegal Instruction - 4. */ + .long trap /* Divide by zero - 5. */ + .long trap /* CHK, CHK2 Instructions - 6. */ + .long trap /* TRAPcc, TRAPV Instructions - 7. */ + .long trap /* Privilege Violation - 8. */ + .long trap /* Trace - 9. */ + .long trap /* Line 1010 Emulator - 10. */ + .long trap /* Line 1111 Emualtor - 11. */ + .long trap /* Harware Breakpoint - 12. */ + .long trap /* (Reserved for Coprocessor Protocol Violation)- 13. */ + .long trap /* Format Error - 14. */ + .long trap /* Uninitialized Interrupt - 15. */ + .long trap /* (Unassigned, Reserver) - 16. */ + .long trap /* (Unassigned, Reserver) - 17. */ + .long trap /* (Unassigned, Reserver) - 18. */ + .long trap /* (Unassigned, Reserver) - 19. */ + .long trap /* (Unassigned, Reserver) - 20. */ + .long trap /* (Unassigned, Reserver) - 21. */ + .long trap /* (Unassigned, Reserver) - 22. */ + .long trap /* (Unassigned, Reserver) - 23. */ + .long trap /* Spurious Interrupt - 24. */ + .long trap /* Level 1 Interrupt Autovector - 25. */ + .long trap /* Level 2 Interrupt Autovector - 26. */ + .long trap /* Level 3 Interrupt Autovector - 27. */ + .long trap /* Level 4 Interrupt Autovector - 28. */ + .long trap /* Level 5 Interrupt Autovector - 29. */ + .long trap /* Level 6 Interrupt Autovector - 30. */ + .long trap /* Level 7 Interrupt Autovector - 31. */ + .long system_call /* Trap Instruction Vectors 0 - 32. */ + .long trap /* Trap Instruction Vectors 1 - 33. */ + .long trap /* Trap Instruction Vectors 2 - 34. */ + .long trap /* Trap Instruction Vectors 3 - 35. */ + .long trap /* Trap Instruction Vectors 4 - 36. */ + .long trap /* Trap Instruction Vectors 5 - 37. */ + .long trap /* Trap Instruction Vectors 6 - 38. */ + .long trap /* Trap Instruction Vectors 7 - 39. */ + .long trap /* Trap Instruction Vectors 8 - 40. */ + .long trap /* Trap Instruction Vectors 9 - 41. */ + .long trap /* Trap Instruction Vectors 10 - 42. */ + .long trap /* Trap Instruction Vectors 11 - 43. */ + .long trap /* Trap Instruction Vectors 12 - 44. */ + .long trap /* Trap Instruction Vectors 13 - 45. */ + .long trap /* Trap Instruction Vectors 14 - 46. */ + .long trap /* Trap Instruction Vectors 15 - 47. */ + .long 0 /* (Reserved for Coprocessor) - 48. */ + .long 0 /* (Reserved for Coprocessor) - 49. */ + .long 0 /* (Reserved for Coprocessor) - 50. */ + .long 0 /* (Reserved for Coprocessor) - 51. */ + .long 0 /* (Reserved for Coprocessor) - 52. */ + .long 0 /* (Reserved for Coprocessor) - 53. */ + .long 0 /* (Reserved for Coprocessor) - 54. */ + .long 0 /* (Reserved for Coprocessor) - 55. */ + .long 0 /* (Reserved for Coprocessor) - 56. */ + .long 0 /* (Reserved for Coprocessor) - 57. */ + .long 0 /* (Reserved for Coprocessor) - 58. */ + .long 0 /* (Unassigned, Reserved) - 59. */ + .long 0 /* (Unassigned, Reserved) - 60. */ + .long 0 /* (Unassigned, Reserved) - 61. */ + .long 0 /* (Unassigned, Reserved) - 62. */ + .long 0 /* (Unassigned, Reserved) - 63. */ + /* The assignment of these vectors to the CPM is */ + /* dependent on the configuration of the CPM vba */ + /* fields. */ + .long 0 /* (User-Defined Vectors 1) CPM Error - 64. */ + .long 0 /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */ + .long 0 /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */ + .long 0 /* (User-Defined Vectors 4) CPM SMC2 / PIP - 67. */ + .long 0 /* (User-Defined Vectors 5) CPM SMC1 - 68. */ + .long 0 /* (User-Defined Vectors 6) CPM SPI - 69. */ + .long 0 /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */ + .long 0 /* (User-Defined Vectors 8) CPM Timer 4 - 71. */ + .long 0 /* (User-Defined Vectors 9) CPM Reserved - 72. */ + .long 0 /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */ + .long 0 /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */ + .long 0 /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */ + .long 0 /* (User-Defined Vectors 13) CPM Timer 3 - 76. */ + .long 0 /* (User-Defined Vectors 14) CPM Reserved - 77. */ + .long 0 /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */ + .long 0 /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */ + .long 0 /* (User-Defined Vectors 17) CPM Reserved - 80. */ + .long 0 /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */ + .long 0 /* (User-Defined Vectors 19) CPM Timer 2 - 82. */ + .long 0 /* (User-Defined Vectors 21) CPM Reserved - 83. */ + .long 0 /* (User-Defined Vectors 22) CPM IDMA2 - 84. */ + .long 0 /* (User-Defined Vectors 23) CPM IDMA1 - 85. */ + .long 0 /* (User-Defined Vectors 24) CPM SDMA Bus Err - 86. */ + .long 0 /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */ + .long 0 /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */ + .long 0 /* (User-Defined Vectors 27) CPM Timer 1 - 89. */ + .long 0 /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */ + .long 0 /* (User-Defined Vectors 29) CPM SCC 4 - 91. */ + .long 0 /* (User-Defined Vectors 30) CPM SCC 3 - 92. */ + .long 0 /* (User-Defined Vectors 31) CPM SCC 2 - 93. */ + .long 0 /* (User-Defined Vectors 32) CPM SCC 1 - 94. */ + .long 0 /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */ + /* I don't think anything uses the vectors after here. */ + .long 0 /* (User-Defined Vectors 34) - 96. */ + .long 0,0,0,0,0 /* (User-Defined Vectors 35 - 39). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 40 - 49). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 50 - 59). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 60 - 69). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 70 - 79). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 80 - 89). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 90 - 99). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 100 - 109). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 110 - 119). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 120 - 129). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 130 - 139). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 140 - 149). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 150 - 159). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 160 - 169). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 170 - 179). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 180 - 189). */ + .long 0,0,0 /* (User-Defined Vectors 190 - 192). */ +.text +ignore: rte -- GitLab From 883f64510718e7df9abbfeec4748d92745d8cc3e Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Mon, 12 Sep 2005 09:13:32 +0800 Subject: [PATCH 473/563] [PATCH] i810fb: Fix oops if CONFIG_FB_I810_I2C is set to no Reported by: Manuel Lauss <mano@roarinelk.homelinux.net> compiled with CONFIG_FB_I810_I2C = n and CONFIG_FB_I810 = y it oopses at boot in file drivers/video/i810/i810_main.c:1884 ... Unable to handle kernel NULL pointer dereference at virtual address 00000054 printing eip: c02543c0 *pde = 00000000 Oops: 0000 [#1] last sysfs file: Modules linked in: CPU: 0 EIP: 0060:[<c02543c0>] Not tainted VLI EFLAGS: 00010286 (2.6.13-mm2) EIP is at i810fb_find_init_mode+0x53/0x93 eax: c113ddd4 ebx: c1194000 ecx: c04be2dd edx: c1194000 esi: c1194008 edi: c113ddd4 ebp: c1194240 esp: c113ddcc ds: 007b es: 007b ss: 0068 struct fb_monspecs *specs is initialized to NULL causing the oops. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/i810/i810_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 7018ffffcbc4e..6f11989f54e3f 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -950,7 +950,7 @@ static int i810_check_params(struct fb_var_screeninfo *var, struct fb_info *info) { struct i810fb_par *par = (struct i810fb_par *) info->par; - int line_length, vidmem, mode_valid = 0; + int line_length, vidmem, mode_valid = 0, retval = 0; u32 vyres = var->yres_virtual, vxres = var->xres_virtual; /* * Memory limit @@ -1026,10 +1026,11 @@ static int i810_check_params(struct fb_var_screeninfo *var, printk("i810fb: invalid video mode%s\n", default_sync ? "" : ". Specifying " "vsyncN/hsyncN parameters may help"); + retval = -EINVAL; } } - return 0; + return retval; } /** @@ -1830,7 +1831,7 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info) { struct fb_videomode mode; struct fb_var_screeninfo var; - struct fb_monspecs *specs = NULL; + struct fb_monspecs *specs = &info->monspecs; int found = 0; #ifdef CONFIG_FB_I810_I2C int i; @@ -1853,12 +1854,11 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info) if (!err) printk("i810fb_init_pci: DDC probe successful\n"); - fb_edid_to_monspecs(par->edid, &info->monspecs); + fb_edid_to_monspecs(par->edid, specs); - if (info->monspecs.modedb == NULL) + if (specs->modedb == NULL) printk("i810fb_init_pci: Unable to get Mode Database\n"); - specs = &info->monspecs; fb_videomode_to_modelist(specs->modedb, specs->modedb_len, &info->modelist); if (specs->modedb != NULL) { -- GitLab From 595e8a97f48619fe7952f31259d3e61af9118f49 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Mon, 12 Sep 2005 09:15:16 +0800 Subject: [PATCH 474/563] [PATCH] i810fb: Restore xres and yres option parameters If i810fb successfully probed for the EDID, it will disregard the boot option parameters 'xres' and 'yres'. Fix this regression. Excellent testing done by Manuel Lauss <mano@roarinelk.homelinux.net>. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/i810/i810_main.c | 52 +++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 6f11989f54e3f..78feded409456 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -95,18 +95,18 @@ static struct pci_driver i810fb_driver = { static char *mode_option __devinitdata = NULL; static int vram __devinitdata = 4; static int bpp __devinitdata = 8; -static int mtrr __devinitdata = 0; -static int accel __devinitdata = 0; -static int hsync1 __devinitdata = 0; -static int hsync2 __devinitdata = 0; -static int vsync1 __devinitdata = 0; -static int vsync2 __devinitdata = 0; -static int xres __devinitdata = 640; -static int yres __devinitdata = 480; -static int vyres __devinitdata = 0; -static int sync __devinitdata = 0; -static int ext_vga __devinitdata = 0; -static int dcolor __devinitdata = 0; +static int mtrr __devinitdata; +static int accel __devinitdata; +static int hsync1 __devinitdata; +static int hsync2 __devinitdata; +static int vsync1 __devinitdata; +static int vsync2 __devinitdata; +static int xres __devinitdata; +static int yres __devinitdata; +static int vyres __devinitdata; +static int sync __devinitdata; +static int ext_vga __devinitdata; +static int dcolor __devinitdata; /*------------------------------------------------------------*/ @@ -1725,12 +1725,21 @@ static void __devinit i810_init_defaults(struct i810fb_par *par, if (bpp < 8) bpp = 8; + par->i810fb_ops = i810fb_ops; + + if (xres) + info->var.xres = xres; + else + info->var.xres = 640; + + if (yres) + info->var.yres = yres; + else + info->var.yres = 480; + if (!vyres) - vyres = (vram << 20)/(xres*bpp >> 3); + vyres = (vram << 20)/(info->var.xres*bpp >> 3); - par->i810fb_ops = i810fb_ops; - info->var.xres = xres; - info->var.yres = yres; info->var.yres_virtual = vyres; info->var.bits_per_pixel = bpp; @@ -1862,7 +1871,16 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info) fb_videomode_to_modelist(specs->modedb, specs->modedb_len, &info->modelist); if (specs->modedb != NULL) { - if (specs->misc & FB_MISC_1ST_DETAIL) { + if (xres && yres) { + struct fb_videomode *m; + + if ((m = fb_find_best_mode(&var, &info->modelist))) { + mode = *m; + found = 1; + } + } + + if (!found && specs->misc & FB_MISC_1ST_DETAIL) { for (i = 0; i < specs->modedb_len; i++) { if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { mode = specs->modedb[i]; -- GitLab From 747a5054c0663a21c440524bdac1bca31be0d20e Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Mon, 12 Sep 2005 09:16:47 +0800 Subject: [PATCH 475/563] [PATCH] i810fb: Change option ext_vga to extvga to match documentation Reported by: Manuel Lauss <mano@roarinelk.homelinux.net> He was getting random initial video modes depending on the kernel configuration. His option line includes 'extvga'. The i810fb documentation describes the option 'extvga', however the driver accepts 'ext_vga'. Besides 'extvga' being ignored by i810fb, it also confuses the option parser of i810fb and assigns 'extvga' to 'mode_option'. This leads to an incorrect video mode at boot time. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/video/i810/i810_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 78feded409456..0dbc9ddb6766e 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -105,7 +105,7 @@ static int xres __devinitdata; static int yres __devinitdata; static int vyres __devinitdata; static int sync __devinitdata; -static int ext_vga __devinitdata; +static int extvga __devinitdata; static int dcolor __devinitdata; /*------------------------------------------------------------*/ @@ -1766,7 +1766,7 @@ static void __devinit i810_init_device(struct i810fb_par *par) i810_init_cursor(par); /* mvo: enable external vga-connector (for laptops) */ - if (ext_vga) { + if (extvga) { i810_writel(HVSYNC, mmio, 0); i810_writel(PWR_CLKC, mmio, 3); } @@ -1921,8 +1921,8 @@ static int __devinit i810fb_setup(char *options) mtrr = 1; else if (!strncmp(this_opt, "accel", 5)) accel = 1; - else if (!strncmp(this_opt, "ext_vga", 7)) - ext_vga = 1; + else if (!strncmp(this_opt, "extvga", 6)) + extvga = 1; else if (!strncmp(this_opt, "sync", 4)) sync = 1; else if (!strncmp(this_opt, "vram:", 5)) @@ -2151,8 +2151,8 @@ module_param(accel, bool, 0); MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)"); module_param(mtrr, bool, 0); MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)"); -module_param(ext_vga, bool, 0); -MODULE_PARM_DESC(ext_vga, "Enable external VGA connector (default = 0)"); +module_param(extvga, bool, 0); +MODULE_PARM_DESC(extvga, "Enable external VGA connector (default = 0)"); module_param(sync, bool, 0); MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing" " (default = 0)"); -- GitLab From c93a777103263c2a610a49771c6336f7a53d8ab7 Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" <adaplas@gmail.com> Date: Mon, 12 Sep 2005 09:18:12 +0800 Subject: [PATCH 476/563] [PATCH] i810fb: Update i810fb documentation Update i810fb documentation to describe new features and configuration changes. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/fb/intel810.txt | 56 +++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/Documentation/fb/intel810.txt b/Documentation/fb/intel810.txt index fd68b162e4a13..4f0d6bc789ef0 100644 --- a/Documentation/fb/intel810.txt +++ b/Documentation/fb/intel810.txt @@ -5,6 +5,7 @@ Intel 810/815 Framebuffer driver March 17, 2002 First Released: July 2001 + Last Update: September 12, 2005 ================================================================ A. Introduction @@ -44,6 +45,8 @@ B. Features - Hardware Cursor Support + - Supports EDID probing either by DDC/I2C or through the BIOS + C. List of available options a. "video=i810fb" @@ -52,14 +55,17 @@ C. List of available options Recommendation: required b. "xres:<value>" - select horizontal resolution in pixels + select horizontal resolution in pixels. (This parameter will be + ignored if 'mode_option' is specified. See 'o' below). Recommendation: user preference (default = 640) c. "yres:<value>" select vertical resolution in scanlines. If Discrete Video Timings - is enabled, this will be ignored and computed as 3*xres/4. + is enabled, this will be ignored and computed as 3*xres/4. (This + parameter will be ignored if 'mode_option' is specified. See 'o' + below) Recommendation: user preference (default = 480) @@ -86,7 +92,8 @@ C. List of available options g. "hsync1/hsync2:<value>" select the minimum and maximum Horizontal Sync Frequency of the monitor in KHz. If a using a fixed frequency monitor, hsync1 must - be equal to hsync2. + be equal to hsync2. If EDID probing is successful, these will be + ignored and values will be taken from the EDID block. Recommendation: check monitor manual for correct values default (29/30) @@ -94,7 +101,8 @@ C. List of available options h. "vsync1/vsync2:<value>" select the minimum and maximum Vertical Sync Frequency of the monitor in Hz. You can also use this option to lock your monitor's refresh - rate. + rate. If EDID probing is successful, these will be ignored and values + will be taken from the EDID block. Recommendation: check monitor manual for correct values (default = 60/60) @@ -154,7 +162,11 @@ C. List of available options Recommendation: do not set (default = not set) - + o. <xres>x<yres>[-<bpp>][@<refresh>] + The driver will now accept specification of boot mode option. If this + is specified, the options 'xres' and 'yres' will be ignored. See + Documentation/fb/modedb.txt for usage. + D. Kernel booting Separate each option/option-pair by commas (,) and the option from its value @@ -176,7 +188,10 @@ will be computed based on the hsync1/hsync2 and vsync1/vsync2 values. IMPORTANT: You must include hsync1, hsync2, vsync1 and vsync2 to enable video modes -better than 640x480 at 60Hz. +better than 640x480 at 60Hz. HOWEVER, if your chipset/display combination +supports I2C and has an EDID block, you can safely exclude hsync1, hsync2, +vsync1 and vsync2 parameters. These parameters will be taken from the EDID +block. E. Module options @@ -217,32 +232,21 @@ F. Setup This is required. The option is under "Character Devices" d. Under "Graphics Support", select "Intel 810/815" either statically - or as a module. Choose "use VESA GTF for video timings" if you - need to maximize the capability of your display. To be on the + or as a module. Choose "use VESA Generalized Timing Formula" if + you need to maximize the capability of your display. To be on the safe side, you can leave this unselected. - e. If you want a framebuffer console, enable it under "Console + e. If you want support for DDC/I2C probing (Plug and Play Displays), + set 'Enable DDC Support' to 'y'. To make this option appear, set + 'use VESA Generalized Timing Formula' to 'y'. + + f. If you want a framebuffer console, enable it under "Console Drivers" - f. Compile your kernel. + g. Compile your kernel. - g. Load the driver as described in section D and E. + h. Load the driver as described in section D and E. - Optional: - h. If you are going to run XFree86 with its native drivers, the - standard XFree86 4.1.0 and 4.2.0 drivers should work as is. - However, there's a bug in the XFree86 i810 drivers. It attempts - to use XAA even when switched to the console. This will crash - your server. I have a fix at this site: - - http://i810fb.sourceforge.net. - - You can either use the patch, or just replace - - /usr/X11R6/lib/modules/drivers/i810_drv.o - - with the one provided at the website. - i. Try the DirectFB (http://www.directfb.org) + the i810 gfxdriver patch to see the chipset in action (or inaction :-). -- GitLab From 4267292b0f368c1633ff3316a53b5f7fbada95f8 Mon Sep 17 00:00:00 2001 From: Paul Mackerras <paulus@samba.org> Date: Mon, 12 Sep 2005 17:17:36 +1000 Subject: [PATCH 477/563] ppc64: Set up PCI tree from Open Firmware device tree This adds code which gives us the option on ppc64 of instantiating the PCI tree (the tree of pci_bus and pci_dev structs) from the Open Firmware device tree rather than by probing PCI configuration space. The OF device tree has a node for each PCI device and bridge in the system, with properties that tell us what addresses the firmware has configured for them and other details. There are a couple of reasons why this is needed. First, on systems with a hypervisor, there is a PCI-PCI bridge per slot under the PCI host bridges. These PCI-PCI bridges have special isolation features for virtualization. We can't write to their config space, and we are not supposed to be reading their config space either. The firmware tells us about the address ranges that they pass in the OF device tree. Secondly, on powermacs, the interrupt controller is in a PCI device that may be behind a PCI-PCI bridge. If we happened to take an interrupt just at the point when the device or a bridge on the path to it was disabled for probing, we would crash when we try to access the interrupt controller. I have implemented a platform-specific function which is called for each PCI bridge (host or PCI-PCI) to say whether the code should look in the device tree or use normal PCI probing for the devices under that bridge. On pSeries machines we use the device tree if we're running under a hypervisor, otherwise we use normal probing. On powermacs we use normal probing for the AGP bridge, since the device for the AGP bridge itself isn't shown in the device tree (at least on my G5), and the device tree for everything else. This has been tested on a dual G5 powermac, a partition on a POWER5 machine (running under the hypervisor), and a legacy iSeries partition. Signed-off-by: Paul Mackerras <paulus@samba.org> --- arch/ppc64/kernel/pSeries_setup.c | 8 + arch/ppc64/kernel/pci.c | 425 +++++++++++++++++++++++------- arch/ppc64/kernel/pmac_setup.c | 13 + include/asm-ppc64/machdep.h | 1 + include/asm-ppc64/pci-bridge.h | 5 + 5 files changed, 362 insertions(+), 90 deletions(-) diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index 9490b6c5b1736..bfadccc7b8be7 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -590,6 +590,13 @@ static int pseries_shared_idle(void) return 0; } +static int pSeries_pci_probe_mode(struct pci_bus *bus) +{ + if (systemcfg->platform & PLATFORM_LPAR) + return PCI_PROBE_DEVTREE; + return PCI_PROBE_NORMAL; +} + struct machdep_calls __initdata pSeries_md = { .probe = pSeries_probe, .setup_arch = pSeries_setup_arch, @@ -597,6 +604,7 @@ struct machdep_calls __initdata pSeries_md = { .get_cpuinfo = pSeries_get_cpuinfo, .log_error = pSeries_log_error, .pcibios_fixup = pSeries_final_fixup, + .pci_probe_mode = pSeries_pci_probe_mode, .irq_bus_setup = pSeries_irq_bus_setup, .restart = rtas_restart, .power_off = rtas_power_off, diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index 8447dcc2c2b3f..861138ad092c5 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -51,6 +51,10 @@ unsigned long io_page_mask; EXPORT_SYMBOL(io_page_mask); +#ifdef CONFIG_PPC_MULTIPLATFORM +static void fixup_resource(struct resource *res, struct pci_dev *dev); +static void do_bus_setup(struct pci_bus *bus); +#endif unsigned int pcibios_assign_all_busses(void) { @@ -225,10 +229,287 @@ static void __init pcibios_claim_of_setup(void) } #endif +#ifdef CONFIG_PPC_MULTIPLATFORM +static u32 get_int_prop(struct device_node *np, const char *name, u32 def) +{ + u32 *prop; + int len; + + prop = (u32 *) get_property(np, name, &len); + if (prop && len >= 4) + return *prop; + return def; +} + +static unsigned int pci_parse_of_flags(u32 addr0) +{ + unsigned int flags = 0; + + if (addr0 & 0x02000000) { + flags |= IORESOURCE_MEM; + if (addr0 & 0x40000000) + flags |= IORESOURCE_PREFETCH; + } else if (addr0 & 0x01000000) + flags |= IORESOURCE_IO; + return flags; +} + +#define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1]) + +static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) +{ + u64 base, size; + unsigned int flags; + struct resource *res; + u32 *addrs, i; + int proplen; + + addrs = (u32 *) get_property(node, "assigned-addresses", &proplen); + if (!addrs) + return; + for (; proplen >= 20; proplen -= 20, addrs += 5) { + flags = pci_parse_of_flags(addrs[0]); + if (!flags) + continue; + base = GET_64BIT(addrs, 1); + size = GET_64BIT(addrs, 3); + if (!size) + continue; + i = addrs[0] & 0xff; + if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { + res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; + } else if (i == dev->rom_base_reg) { + res = &dev->resource[PCI_ROM_RESOURCE]; + flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE; + } else { + printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i); + continue; + } + res->start = base; + res->end = base + size - 1; + res->flags = flags; + res->name = pci_name(dev); + fixup_resource(res, dev); + } +} + +static struct pci_dev *of_create_pci_dev(struct device_node *node, + struct pci_bus *bus, int devfn) +{ + struct pci_dev *dev; + const char *type; + + dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); + if (!dev) + return NULL; + type = get_property(node, "device_type", NULL); + if (type == NULL) + type = ""; + + memset(dev, 0, sizeof(struct pci_dev)); + dev->bus = bus; + dev->sysdata = node; + dev->dev.parent = bus->bridge; + dev->dev.bus = &pci_bus_type; + dev->devfn = devfn; + dev->multifunction = 0; /* maybe a lie? */ + + dev->vendor = get_int_prop(node, "vendor-id", 0xffff); + dev->device = get_int_prop(node, "device-id", 0xffff); + dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0); + dev->subsystem_device = get_int_prop(node, "subsystem-id", 0); + + dev->cfg_size = 256; /*pci_cfg_space_size(dev);*/ + + sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), + dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); + dev->class = get_int_prop(node, "class-code", 0); + + dev->current_state = 4; /* unknown power state */ + + if (!strcmp(type, "pci")) { + /* a PCI-PCI bridge */ + dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; + dev->rom_base_reg = PCI_ROM_ADDRESS1; + } else if (!strcmp(type, "cardbus")) { + dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; + } else { + dev->hdr_type = PCI_HEADER_TYPE_NORMAL; + dev->rom_base_reg = PCI_ROM_ADDRESS; + dev->irq = NO_IRQ; + if (node->n_intrs > 0) { + dev->irq = node->intrs[0].line; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, + dev->irq); + } + } + + pci_parse_of_addrs(node, dev); + + pci_device_add(dev, bus); + + /* XXX pci_scan_msi_device(dev); */ + + return dev; +} + +static void of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev); + +static void __devinit of_scan_bus(struct device_node *node, + struct pci_bus *bus) +{ + struct device_node *child = NULL; + u32 *reg; + int reglen, devfn; + struct pci_dev *dev; + + while ((child = of_get_next_child(node, child)) != NULL) { + reg = (u32 *) get_property(child, "reg", ®len); + if (reg == NULL || reglen < 20) + continue; + devfn = (reg[0] >> 8) & 0xff; + /* create a new pci_dev for this device */ + dev = of_create_pci_dev(child, bus, devfn); + if (!dev) + continue; + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + of_scan_pci_bridge(child, dev); + } + + do_bus_setup(bus); +} + +static void __devinit of_scan_pci_bridge(struct device_node *node, + struct pci_dev *dev) +{ + struct pci_bus *bus; + u32 *busrange, *ranges; + int len, i, mode; + struct resource *res; + unsigned int flags; + u64 size; + + /* parse bus-range property */ + busrange = (u32 *) get_property(node, "bus-range", &len); + if (busrange == NULL || len != 8) { + printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n", + node->full_name); + return; + } + ranges = (u32 *) get_property(node, "ranges", &len); + if (ranges == NULL) { + printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n", + node->full_name); + return; + } + + bus = pci_add_new_bus(dev->bus, dev, busrange[0]); + if (!bus) { + printk(KERN_ERR "Failed to create pci bus for %s\n", + node->full_name); + return; + } + + bus->primary = dev->bus->number; + bus->subordinate = busrange[1]; + bus->bridge_ctl = 0; + bus->sysdata = node; + + /* parse ranges property */ + /* PCI #address-cells == 3 and #size-cells == 2 always */ + res = &dev->resource[PCI_BRIDGE_RESOURCES]; + for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) { + res->flags = 0; + bus->resource[i] = res; + ++res; + } + i = 1; + for (; len >= 32; len -= 32, ranges += 8) { + flags = pci_parse_of_flags(ranges[0]); + size = GET_64BIT(ranges, 6); + if (flags == 0 || size == 0) + continue; + if (flags & IORESOURCE_IO) { + res = bus->resource[0]; + if (res->flags) { + printk(KERN_ERR "PCI: ignoring extra I/O range" + " for bridge %s\n", node->full_name); + continue; + } + } else { + if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) { + printk(KERN_ERR "PCI: too many memory ranges" + " for bridge %s\n", node->full_name); + continue; + } + res = bus->resource[i]; + ++i; + } + res->start = GET_64BIT(ranges, 1); + res->end = res->start + size - 1; + res->flags = flags; + fixup_resource(res, dev); + } + sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), + bus->number); + + mode = PCI_PROBE_NORMAL; + if (ppc_md.pci_probe_mode) + mode = ppc_md.pci_probe_mode(bus); + if (mode == PCI_PROBE_DEVTREE) + of_scan_bus(node, bus); + else if (mode == PCI_PROBE_NORMAL) + pci_scan_child_bus(bus); +} +#endif /* CONFIG_PPC_MULTIPLATFORM */ + +static void __devinit scan_phb(struct pci_controller *hose) +{ + struct pci_bus *bus; + struct device_node *node = hose->arch_data; + int i, mode; + struct resource *res; + + bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node); + if (bus == NULL) { + printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", + hose->global_number); + return; + } + bus->secondary = hose->first_busno; + hose->bus = bus; + + bus->resource[0] = res = &hose->io_resource; + if (res->flags && request_resource(&ioport_resource, res)) + printk(KERN_ERR "Failed to request PCI IO region " + "on PCI domain %04x\n", hose->global_number); + + for (i = 0; i < 3; ++i) { + res = &hose->mem_resources[i]; + bus->resource[i+1] = res; + if (res->flags && request_resource(&iomem_resource, res)) + printk(KERN_ERR "Failed to request PCI memory region " + "on PCI domain %04x\n", hose->global_number); + } + + mode = PCI_PROBE_NORMAL; +#ifdef CONFIG_PPC_MULTIPLATFORM + if (ppc_md.pci_probe_mode) + mode = ppc_md.pci_probe_mode(bus); + if (mode == PCI_PROBE_DEVTREE) { + bus->subordinate = hose->last_busno; + of_scan_bus(node, bus); + } +#endif /* CONFIG_PPC_MULTIPLATFORM */ + if (mode == PCI_PROBE_NORMAL) + hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); + pci_bus_add_devices(bus); +} + static int __init pcibios_init(void) { struct pci_controller *hose, *tmp; - struct pci_bus *bus; /* For now, override phys_mem_access_prot. If we need it, * later, we may move that initialization to each ppc_md @@ -242,13 +523,8 @@ static int __init pcibios_init(void) printk("PCI: Probing PCI hardware\n"); /* Scan all of the recorded PCI controllers. */ - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - hose->last_busno = 0xff; - bus = pci_scan_bus(hose->first_busno, hose->ops, - hose->arch_data); - hose->bus = bus; - hose->last_busno = bus->subordinate; - } + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) + scan_phb(hose); #ifndef CONFIG_PPC_ISERIES if (pci_probe_only) @@ -820,120 +1096,89 @@ void phbs_remap_io(void) /* * ppc64 can have multifunction devices that do not respond to function 0. * In this case we must scan all functions. + * XXX this can go now, we use the OF device tree in all the + * cases that caused problems. -- paulus */ int pcibios_scan_all_fns(struct pci_bus *bus, int devfn) { - struct device_node *busdn, *dn; - - if (bus->self) - busdn = pci_device_to_OF_node(bus->self); - else - busdn = bus->sysdata; /* must be a phb */ - - if (busdn == NULL) - return 0; - - /* - * Check to see if there is any of the 8 functions are in the - * device tree. If they are then we need to scan all the - * functions of this slot. - */ - for (dn = busdn->child; dn; dn = dn->sibling) { - struct pci_dn *pdn = dn->data; - if (pdn && (pdn->devfn >> 3) == (devfn >> 3)) - return 1; - } - return 0; } +static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + unsigned long start, end, mask, offset; + + if (res->flags & IORESOURCE_IO) { + offset = (unsigned long)hose->io_base_virt - pci_io_base; + + start = res->start += offset; + end = res->end += offset; + + /* Need to allow IO access to pages that are in the + ISA range */ + if (start < MAX_ISA_PORT) { + if (end > MAX_ISA_PORT) + end = MAX_ISA_PORT; + + start >>= PAGE_SHIFT; + end >>= PAGE_SHIFT; + + /* get the range of pages for the map */ + mask = ((1 << (end+1)) - 1) ^ ((1 << start) - 1); + io_page_mask |= mask; + } + } else if (res->flags & IORESOURCE_MEM) { + res->start += hose->pci_mem_offset; + res->end += hose->pci_mem_offset; + } +} void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, - struct pci_bus *bus) + struct pci_bus *bus) { /* Update device resources. */ - struct pci_controller *hose = pci_bus_to_host(bus); int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - if (dev->resource[i].flags & IORESOURCE_IO) { - unsigned long offset = (unsigned long)hose->io_base_virt - - pci_io_base; - unsigned long start, end, mask; - - start = dev->resource[i].start += offset; - end = dev->resource[i].end += offset; - - /* Need to allow IO access to pages that are in the - ISA range */ - if (start < MAX_ISA_PORT) { - if (end > MAX_ISA_PORT) - end = MAX_ISA_PORT; - - start >>= PAGE_SHIFT; - end >>= PAGE_SHIFT; - - /* get the range of pages for the map */ - mask = ((1 << (end+1))-1) ^ ((1 << start)-1); - io_page_mask |= mask; - } - } - else if (dev->resource[i].flags & IORESOURCE_MEM) { - dev->resource[i].start += hose->pci_mem_offset; - dev->resource[i].end += hose->pci_mem_offset; - } - } + for (i = 0; i < PCI_NUM_RESOURCES; i++) + if (dev->resource[i].flags) + fixup_resource(&dev->resource[i], dev); } EXPORT_SYMBOL(pcibios_fixup_device_resources); -void __devinit pcibios_fixup_bus(struct pci_bus *bus) +static void __devinit do_bus_setup(struct pci_bus *bus) { - struct pci_controller *hose = pci_bus_to_host(bus); - struct pci_dev *dev = bus->self; - struct resource *res; - int i; + struct pci_dev *dev; - if (!dev) { - /* Root bus. */ + ppc_md.iommu_bus_setup(bus); - hose->bus = bus; - bus->resource[0] = res = &hose->io_resource; + list_for_each_entry(dev, &bus->devices, bus_list) + ppc_md.iommu_dev_setup(dev); - if (res->flags && request_resource(&ioport_resource, res)) - printk(KERN_ERR "Failed to request IO on " - "PCI domain %d\n", pci_domain_nr(bus)); + if (ppc_md.irq_bus_setup) + ppc_md.irq_bus_setup(bus); +} - for (i = 0; i < 3; ++i) { - res = &hose->mem_resources[i]; - bus->resource[i+1] = res; - if (res->flags && request_resource(&iomem_resource, res)) - printk(KERN_ERR "Failed to request MEM on " - "PCI domain %d\n", - pci_domain_nr(bus)); - } - } else if (pci_probe_only && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { +void __devinit pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev = bus->self; + + if (dev && pci_probe_only && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { /* This is a subordinate bridge */ pci_read_bridge_bases(bus); pcibios_fixup_device_resources(dev, bus); } - ppc_md.iommu_bus_setup(bus); - - list_for_each_entry(dev, &bus->devices, bus_list) - ppc_md.iommu_dev_setup(dev); - - if (ppc_md.irq_bus_setup) - ppc_md.irq_bus_setup(bus); + do_bus_setup(bus); if (!pci_probe_only) return; - list_for_each_entry(dev, &bus->devices, bus_list) { + list_for_each_entry(dev, &bus->devices, bus_list) if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) pcibios_fixup_device_resources(dev, bus); - } } EXPORT_SYMBOL(pcibios_fixup_bus); diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index e7f695dcd8c8d..325426c7bed00 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -477,6 +477,18 @@ static int __init pmac_probe(int platform) return 1; } +static int pmac_probe_mode(struct pci_bus *bus) +{ + struct device_node *node = bus->sysdata; + + /* We need to use normal PCI probing for the AGP bus, + since the device for the AGP bridge isn't in the tree. */ + if (bus->self == NULL && device_is_compatible(node, "u3-agp")) + return PCI_PROBE_NORMAL; + + return PCI_PROBE_DEVTREE; +} + struct machdep_calls __initdata pmac_md = { #ifdef CONFIG_HOTPLUG_CPU .cpu_die = generic_mach_cpu_die, @@ -488,6 +500,7 @@ struct machdep_calls __initdata pmac_md = { .init_IRQ = pmac_init_IRQ, .get_irq = mpic_get_irq, .pcibios_fixup = pmac_pcibios_fixup, + .pci_probe_mode = pmac_probe_mode, .restart = pmac_restart, .power_off = pmac_power_off, .halt = pmac_halt, diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h index 9a1ef4427ed2d..7b25738c111f1 100644 --- a/include/asm-ppc64/machdep.h +++ b/include/asm-ppc64/machdep.h @@ -88,6 +88,7 @@ struct machdep_calls { /* PCI stuff */ void (*pcibios_fixup)(void); + int (*pci_probe_mode)(struct pci_bus *); void (*restart)(char *cmd); void (*power_off)(void); diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h index 6b4a5b1f695e9..d8991389ab396 100644 --- a/include/asm-ppc64/pci-bridge.h +++ b/include/asm-ppc64/pci-bridge.h @@ -119,5 +119,10 @@ static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus) return PCI_DN(busdn)->phb; } +/* Return values for ppc_md.pci_probe_mode function */ +#define PCI_PROBE_NONE -1 /* Don't look at this bus at all */ +#define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */ +#define PCI_PROBE_DEVTREE 1 /* Instantiate from device tree */ + #endif #endif /* __KERNEL__ */ -- GitLab From 962bca7f389229a30ced441d7b37f55f203006a2 Mon Sep 17 00:00:00 2001 From: Robert Jennings <rcjenn@austin.ibm.com> Date: Sat, 10 Sep 2005 16:01:07 +1000 Subject: [PATCH 478/563] [PATCH] ppc64: Add PTRACE_{GET|SET}VRREGS The ptrace get and set methods for VMX/Altivec registers present in the ppc tree were missing for ppc64. This patch adds the 32-bit and 64-bit methods. Updated with the suggestions from Anton following the lines of his code snippet. Added: - flush_altivec_to_thread calls as suggested by Anton - piecewise copy of structure to preserve 32-bit vrsave data as per Anton (I consolidated the 32 and 64bit versions with 2 helper macros - Anton) Signed-off-by: Robert C Jennings <rcjenn@austin.ibm.com> Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org> --- arch/ppc64/kernel/ptrace.c | 15 +++++++ arch/ppc64/kernel/ptrace32.c | 15 +++++++ include/asm-ppc64/ptrace-common.h | 72 +++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index 2993f108d96d3..bf7116d4c4c26 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c @@ -17,6 +17,7 @@ * this archive for more details. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> @@ -274,6 +275,20 @@ int sys_ptrace(long request, long pid, long addr, long data) break; } +#ifdef CONFIG_ALTIVEC + case PTRACE_GETVRREGS: + /* Get the child altivec register state. */ + flush_altivec_to_thread(child); + ret = get_vrregs((unsigned long __user *)data, child); + break; + + case PTRACE_SETVRREGS: + /* Set the child altivec register state. */ + flush_altivec_to_thread(child); + ret = set_vrregs(child, (unsigned long __user *)data); + break; +#endif + default: ret = ptrace_request(child, request, addr, data); break; diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c index 16436426c7e24..4d1568c946cce 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/ppc64/kernel/ptrace32.c @@ -17,6 +17,7 @@ * this archive for more details. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> @@ -409,6 +410,20 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) ret = put_user(child->ptrace_message, (unsigned int __user *) data); break; +#ifdef CONFIG_ALTIVEC + case PTRACE_GETVRREGS: + /* Get the child altivec register state. */ + flush_altivec_to_thread(child); + ret = get_vrregs((unsigned long __user *)data, child); + break; + + case PTRACE_SETVRREGS: + /* Set the child altivec register state. */ + flush_altivec_to_thread(child); + ret = set_vrregs(child, (unsigned long __user *)data); + break; +#endif + default: ret = ptrace_request(child, request, addr, data); break; diff --git a/include/asm-ppc64/ptrace-common.h b/include/asm-ppc64/ptrace-common.h index af03547f9c7ed..bd0f84c27bd0b 100644 --- a/include/asm-ppc64/ptrace-common.h +++ b/include/asm-ppc64/ptrace-common.h @@ -11,6 +11,9 @@ #ifndef _PPC64_PTRACE_COMMON_H #define _PPC64_PTRACE_COMMON_H + +#include <linux/config.h> + /* * Set of msr bits that gdb can change on behalf of a process. */ @@ -69,4 +72,73 @@ static inline void clear_single_step(struct task_struct *task) clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP); } +#ifdef CONFIG_ALTIVEC +/* + * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. + * The transfer totals 34 quadword. Quadwords 0-31 contain the + * corresponding vector registers. Quadword 32 contains the vscr as the + * last word (offset 12) within that quadword. Quadword 33 contains the + * vrsave as the first word (offset 0) within the quadword. + * + * This definition of the VMX state is compatible with the current PPC32 + * ptrace interface. This allows signal handling and ptrace to use the + * same structures. This also simplifies the implementation of a bi-arch + * (combined (32- and 64-bit) gdb. + */ + +/* + * Get contents of AltiVec register state in task TASK + */ +static inline int get_vrregs(unsigned long __user *data, + struct task_struct *task) +{ + unsigned long regsize; + + /* copy AltiVec registers VR[0] .. VR[31] */ + regsize = 32 * sizeof(vector128); + if (copy_to_user(data, task->thread.vr, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VSCR */ + regsize = 1 * sizeof(vector128); + if (copy_to_user(data, &task->thread.vscr, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VRSAVE */ + if (put_user(task->thread.vrsave, (u32 __user *)data)) + return -EFAULT; + + return 0; +} + +/* + * Write contents of AltiVec register state into task TASK. + */ +static inline int set_vrregs(struct task_struct *task, + unsigned long __user *data) +{ + unsigned long regsize; + + /* copy AltiVec registers VR[0] .. VR[31] */ + regsize = 32 * sizeof(vector128); + if (copy_from_user(task->thread.vr, data, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VSCR */ + regsize = 1 * sizeof(vector128); + if (copy_from_user(&task->thread.vscr, data, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VRSAVE */ + if (get_user(task->thread.vrsave, (u32 __user *)data)) + return -EFAULT; + + return 0; +} +#endif + #endif /* _PPC64_PTRACE_COMMON_H */ -- GitLab From a0987224dc80b3eb98cc7a135422acbda8538146 Mon Sep 17 00:00:00 2001 From: Anton Blanchard <anton@samba.org> Date: Sat, 10 Sep 2005 16:01:08 +1000 Subject: [PATCH 479/563] [PATCH] ppc64: ptrace cleanups - Remove the PPC_REG* defines - Wrap some more stuff with ifdef __KERNEL__ - Add missing PT_TRAP, PT_DAR, PT_DSISR defines - Add PTRACE_GETEVRREGS/PTRACE_SETEVRREGS, even though we dont use it on ppc64 we dont want to allocate them for something else. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org> --- include/asm-ppc64/ptrace.h | 121 +++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 52 deletions(-) diff --git a/include/asm-ppc64/ptrace.h b/include/asm-ppc64/ptrace.h index c96aad28fc081..a736000d7cf8d 100644 --- a/include/asm-ppc64/ptrace.h +++ b/include/asm-ppc64/ptrace.h @@ -25,56 +25,49 @@ */ #ifndef __ASSEMBLY__ -#define PPC_REG unsigned long + struct pt_regs { - PPC_REG gpr[32]; - PPC_REG nip; - PPC_REG msr; - PPC_REG orig_gpr3; /* Used for restarting system calls */ - PPC_REG ctr; - PPC_REG link; - PPC_REG xer; - PPC_REG ccr; - PPC_REG softe; /* Soft enabled/disabled */ - PPC_REG trap; /* Reason for being here */ - PPC_REG dar; /* Fault registers */ - PPC_REG dsisr; - PPC_REG result; /* Result of a system call */ + unsigned long gpr[32]; + unsigned long nip; + unsigned long msr; + unsigned long orig_gpr3; /* Used for restarting system calls */ + unsigned long ctr; + unsigned long link; + unsigned long xer; + unsigned long ccr; + unsigned long softe; /* Soft enabled/disabled */ + unsigned long trap; /* Reason for being here */ + unsigned long dar; /* Fault registers */ + unsigned long dsisr; + unsigned long result; /* Result of a system call */ }; -#define PPC_REG_32 unsigned int struct pt_regs32 { - PPC_REG_32 gpr[32]; - PPC_REG_32 nip; - PPC_REG_32 msr; - PPC_REG_32 orig_gpr3; /* Used for restarting system calls */ - PPC_REG_32 ctr; - PPC_REG_32 link; - PPC_REG_32 xer; - PPC_REG_32 ccr; - PPC_REG_32 mq; /* 601 only (not used at present) */ - /* Used on APUS to hold IPL value. */ - PPC_REG_32 trap; /* Reason for being here */ - PPC_REG_32 dar; /* Fault registers */ - PPC_REG_32 dsisr; - PPC_REG_32 result; /* Result of a system call */ + unsigned int gpr[32]; + unsigned int nip; + unsigned int msr; + unsigned int orig_gpr3; /* Used for restarting system calls */ + unsigned int ctr; + unsigned int link; + unsigned int xer; + unsigned int ccr; + unsigned int mq; /* 601 only (not used at present) */ + unsigned int trap; /* Reason for being here */ + unsigned int dar; /* Fault registers */ + unsigned int dsisr; + unsigned int result; /* Result of a system call */ }; +#ifdef __KERNEL__ + #define instruction_pointer(regs) ((regs)->nip) + #ifdef CONFIG_SMP extern unsigned long profile_pc(struct pt_regs *regs); #else #define profile_pc(regs) instruction_pointer(regs) #endif -#endif /* __ASSEMBLY__ */ - -#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ - -/* Size of dummy stack frame allocated when calling signal handler. */ -#define __SIGNAL_FRAMESIZE 128 -#define __SIGNAL_FRAMESIZE32 64 - #define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1) #define force_successful_syscall_return() \ @@ -89,6 +82,16 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define TRAP(regs) ((regs)->trap & ~0xF) #define CHECK_FULL_REGS(regs) BUG_ON(regs->trap & 1) +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ + +/* Size of dummy stack frame allocated when calling signal handler. */ +#define __SIGNAL_FRAMESIZE 128 +#define __SIGNAL_FRAMESIZE32 64 + /* * Offsets used by 'ptrace' system call interface. */ @@ -135,17 +138,21 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define PT_XER 37 #define PT_CCR 38 #define PT_SOFTE 39 +#define PT_TRAP 40 +#define PT_DAR 41 +#define PT_DSISR 42 #define PT_RESULT 43 #define PT_FPR0 48 -/* Kernel and userspace will both use this PT_FPSCR value. 32-bit apps will have - * visibility to the asm-ppc/ptrace.h header instead of this one. +/* + * Kernel and userspace will both use this PT_FPSCR value. 32-bit apps will + * have visibility to the asm-ppc/ptrace.h header instead of this one. */ -#define PT_FPSCR (PT_FPR0 + 32) /* each FP reg occupies 1 slot in 64-bit space */ +#define PT_FPSCR (PT_FPR0 + 32) /* each FP reg occupies 1 slot in 64-bit space */ #ifdef __KERNEL__ -#define PT_FPSCR32 (PT_FPR0 + 2*32 + 1) /* each FP reg occupies 2 32-bit userspace slots */ +#define PT_FPSCR32 (PT_FPR0 + 2*32 + 1) /* each FP reg occupies 2 32-bit userspace slots */ #endif #define PT_VR0 82 /* each Vector reg occupies 2 slots in 64-bit */ @@ -173,17 +180,27 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define PTRACE_GETVRREGS 18 #define PTRACE_SETVRREGS 19 -/* Additional PTRACE requests implemented on PowerPC. */ -#define PPC_PTRACE_GETREGS 0x99 /* Get GPRs 0 - 31 */ -#define PPC_PTRACE_SETREGS 0x98 /* Set GPRs 0 - 31 */ -#define PPC_PTRACE_GETFPREGS 0x97 /* Get FPRs 0 - 31 */ -#define PPC_PTRACE_SETFPREGS 0x96 /* Set FPRs 0 - 31 */ -#define PPC_PTRACE_PEEKTEXT_3264 0x95 /* Read word at location ADDR on a 64-bit process from a 32-bit process. */ -#define PPC_PTRACE_PEEKDATA_3264 0x94 /* Read word at location ADDR on a 64-bit process from a 32-bit process. */ -#define PPC_PTRACE_POKETEXT_3264 0x93 /* Write word at location ADDR on a 64-bit process from a 32-bit process. */ -#define PPC_PTRACE_POKEDATA_3264 0x92 /* Write word at location ADDR on a 64-bit process from a 32-bit process. */ -#define PPC_PTRACE_PEEKUSR_3264 0x91 /* Read a register (specified by ADDR) out of the "user area" on a 64-bit process from a 32-bit process. */ -#define PPC_PTRACE_POKEUSR_3264 0x90 /* Write DATA into location ADDR within the "user area" on a 64-bit process from a 32-bit process. */ +/* + * While we dont have 64bit book E processors, we need to reserve the + * relevant ptrace calls for 32bit compatibility. + */ +#if 0 +#define PTRACE_GETEVRREGS 20 +#define PTRACE_SETEVRREGS 21 +#endif +/* Additional PTRACE requests implemented on PowerPC. */ +#define PPC_PTRACE_GETREGS 0x99 /* Get GPRs 0 - 31 */ +#define PPC_PTRACE_SETREGS 0x98 /* Set GPRs 0 - 31 */ +#define PPC_PTRACE_GETFPREGS 0x97 /* Get FPRs 0 - 31 */ +#define PPC_PTRACE_SETFPREGS 0x96 /* Set FPRs 0 - 31 */ + +/* Calls to trace a 64bit program from a 32bit program */ +#define PPC_PTRACE_PEEKTEXT_3264 0x95 +#define PPC_PTRACE_PEEKDATA_3264 0x94 +#define PPC_PTRACE_POKETEXT_3264 0x93 +#define PPC_PTRACE_POKEDATA_3264 0x92 +#define PPC_PTRACE_PEEKUSR_3264 0x91 +#define PPC_PTRACE_POKEUSR_3264 0x90 #endif /* _PPC64_PTRACE_H */ -- GitLab From df09ce4a15bac7b05356b2f00fbb600c5890b1f3 Mon Sep 17 00:00:00 2001 From: Anton Blanchard <anton@samba.org> Date: Sat, 10 Sep 2005 16:01:09 +1000 Subject: [PATCH 480/563] [PATCH] ppc64: Fix up some whitespace issues in ptrace32.c Fix up some whitespace issues in ptrace32.c Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org> --- arch/ppc64/kernel/ptrace32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c index 4d1568c946cce..cbb1e0fb8813a 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/ppc64/kernel/ptrace32.c @@ -406,9 +406,9 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) break; } - case PTRACE_GETEVENTMSG: - ret = put_user(child->ptrace_message, (unsigned int __user *) data); - break; + case PTRACE_GETEVENTMSG: + ret = put_user(child->ptrace_message, (unsigned int __user *) data); + break; #ifdef CONFIG_ALTIVEC case PTRACE_GETVRREGS: -- GitLab From a94d308513bdb2b926b45c11d7ce7fac6d6ca865 Mon Sep 17 00:00:00 2001 From: Anton Blanchard <anton@samba.org> Date: Sat, 10 Sep 2005 16:01:10 +1000 Subject: [PATCH 481/563] [PATCH] ppc64: Add definitions for new PTRACE calls - Add PTRACE_GET_DEBUGREG/PTRACE_SET_DEBUGREG. The definition is as follows: /* * Get or set a debug register. The first 16 are DABR registers and the * second 16 are IABR registers. */ #define PTRACE_GET_DEBUGREG 25 #define PTRACE_SET_DEBUGREG 26 DABR == data breakpoint and IABR = instruction breakpoint in IBM speak. We could split out the IABR into 2 more ptrace calls but I figured there was no need and 16 DABR registers should be more than enough (POWER4/POWER5 have one). - Add 2 new SIGTRAP si_codes: TRAP_HWBKPT and TRAP_BRANCH. I couldnt find any standards on either of these so I copied what ia64 is doing. Again this might be better placed in include/asm-generic/siginfo.h Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org> --- include/asm-powerpc/siginfo.h | 8 ++++++++ include/asm-ppc/ptrace.h | 7 +++++++ include/asm-ppc64/ptrace.h | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/include/asm-powerpc/siginfo.h b/include/asm-powerpc/siginfo.h index 538ea8ef509b9..12f1bce037be7 100644 --- a/include/asm-powerpc/siginfo.h +++ b/include/asm-powerpc/siginfo.h @@ -15,4 +15,12 @@ #include <asm-generic/siginfo.h> +/* + * SIGTRAP si_codes + */ +#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ +#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint or watchpoint */ +#undef NSIGTRAP +#define NSIGTRAP 4 + #endif /* _ASM_POWERPC_SIGINFO_H */ diff --git a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h index 9d4e4ea530c3a..7043c164b5375 100644 --- a/include/asm-ppc/ptrace.h +++ b/include/asm-ppc/ptrace.h @@ -142,4 +142,11 @@ do { \ #define PTRACE_GETEVRREGS 20 #define PTRACE_SETEVRREGS 21 +/* + * Get or set a debug register. The first 16 are DABR registers and the + * second 16 are IABR registers. + */ +#define PTRACE_GET_DEBUGREG 25 +#define PTRACE_SET_DEBUGREG 26 + #endif diff --git a/include/asm-ppc64/ptrace.h b/include/asm-ppc64/ptrace.h index a736000d7cf8d..3a55377f1fd30 100644 --- a/include/asm-ppc64/ptrace.h +++ b/include/asm-ppc64/ptrace.h @@ -189,6 +189,13 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define PTRACE_SETEVRREGS 21 #endif +/* + * Get or set a debug register. The first 16 are DABR registers and the + * second 16 are IABR registers. + */ +#define PTRACE_GET_DEBUGREG 25 +#define PTRACE_SET_DEBUGREG 26 + /* Additional PTRACE requests implemented on PowerPC. */ #define PPC_PTRACE_GETREGS 0x99 /* Get GPRs 0 - 31 */ #define PPC_PTRACE_SETREGS 0x98 /* Set GPRs 0 - 31 */ -- GitLab From fd9648dff6f9797ecc509bcd181706a274dc074d Mon Sep 17 00:00:00 2001 From: Anton Blanchard <anton@samba.org> Date: Sat, 10 Sep 2005 16:01:11 +1000 Subject: [PATCH 482/563] [PATCH] ppc64: Add ptrace data breakpoint support Add hardware data breakpoint support. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org> --- arch/ppc64/kernel/process.c | 34 ++++++++++++++++++++++++++++++ arch/ppc64/kernel/ptrace.c | 13 ++++++++++++ arch/ppc64/kernel/ptrace32.c | 13 ++++++++++++ arch/ppc64/kernel/ras.c | 2 -- arch/ppc64/kernel/signal.c | 9 ++++++++ arch/ppc64/kernel/signal32.c | 8 +++++++ arch/ppc64/mm/fault.c | 31 +++++++++++++++++++++------ arch/ppc64/xmon/privinst.h | 1 - arch/ppc64/xmon/xmon.c | 20 ++++-------------- include/asm-ppc64/hvcall.h | 6 ++++++ include/asm-ppc64/plpar_wrappers.h | 9 ++++++++ include/asm-ppc64/processor.h | 1 + include/asm-ppc64/ptrace-common.h | 20 ++++++++++++++++++ include/asm-ppc64/system.h | 3 +++ 14 files changed, 145 insertions(+), 25 deletions(-) diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index 7a7e027653ad9..887005358eb1f 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -54,6 +54,7 @@ #include <asm/sections.h> #include <asm/tlbflush.h> #include <asm/time.h> +#include <asm/plpar_wrappers.h> #ifndef CONFIG_SMP struct task_struct *last_task_used_math = NULL; @@ -163,7 +164,30 @@ int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) #endif /* CONFIG_ALTIVEC */ +static void set_dabr_spr(unsigned long val) +{ + mtspr(SPRN_DABR, val); +} + +int set_dabr(unsigned long dabr) +{ + int ret = 0; + + if (firmware_has_feature(FW_FEATURE_XDABR)) { + /* We want to catch accesses from kernel and userspace */ + unsigned long flags = H_DABRX_KERNEL|H_DABRX_USER; + ret = plpar_set_xdabr(dabr, flags); + } else if (firmware_has_feature(FW_FEATURE_DABR)) { + ret = plpar_set_dabr(dabr); + } else { + set_dabr_spr(dabr); + } + + return ret; +} + DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); +static DEFINE_PER_CPU(unsigned long, current_dabr); struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *new) @@ -198,6 +222,11 @@ struct task_struct *__switch_to(struct task_struct *prev, new->thread.regs->msr |= MSR_VEC; #endif /* CONFIG_ALTIVEC */ + if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) { + set_dabr(new->thread.dabr); + __get_cpu_var(current_dabr) = new->thread.dabr; + } + flush_tlb_pending(); new_thread = &new->thread; @@ -334,6 +363,11 @@ void flush_thread(void) last_task_used_altivec = NULL; #endif /* CONFIG_ALTIVEC */ #endif /* CONFIG_SMP */ + + if (current->thread.dabr) { + current->thread.dabr = 0; + set_dabr(0); + } } void diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index bf7116d4c4c26..85ed3188a91d0 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c @@ -207,6 +207,19 @@ int sys_ptrace(long request, long pid, long addr, long data) break; } + case PTRACE_GET_DEBUGREG: { + ret = -EINVAL; + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + break; + ret = put_user(child->thread.dabr, + (unsigned long __user *)data); + break; + } + + case PTRACE_SET_DEBUGREG: + ret = ptrace_set_debugreg(child, addr, data); + case PTRACE_DETACH: ret = ptrace_detach(child, data); break; diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c index cbb1e0fb8813a..fb8c22d6084a7 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/ppc64/kernel/ptrace32.c @@ -338,6 +338,19 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) break; } + case PTRACE_GET_DEBUGREG: { + ret = -EINVAL; + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + break; + ret = put_user(child->thread.dabr, (u32 __user *)data); + break; + } + + case PTRACE_SET_DEBUGREG: + ret = ptrace_set_debugreg(child, addr, data); + break; + case PTRACE_DETACH: ret = ptrace_detach(child, data); break; diff --git a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c index 3c00f7bfc1b57..41b97dc9cc0a0 100644 --- a/arch/ppc64/kernel/ras.c +++ b/arch/ppc64/kernel/ras.c @@ -59,8 +59,6 @@ char mce_data_buf[RTAS_ERROR_LOG_MAX] /* This is true if we are using the firmware NMI handler (typically LPAR) */ extern int fwnmi_active; -extern void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr); - static int ras_get_sensor_state_token; static int ras_check_exception_token; diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c index 49a79a55c32de..347112cca3c09 100644 --- a/arch/ppc64/kernel/signal.c +++ b/arch/ppc64/kernel/signal.c @@ -550,6 +550,15 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) /* Whee! Actually deliver the signal. */ if (TRAP(regs) == 0x0C00) syscall_restart(regs, &ka); + + /* + * Reenable the DABR before delivering the signal to + * user space. The DABR will have been cleared if it + * triggered inside the kernel. + */ + if (current->thread.dabr) + set_dabr(current->thread.dabr); + return handle_signal(signr, &ka, &info, oldset, regs); } diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c index 46f4d6cc7fc95..a8b7a5a56bb44 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c @@ -970,6 +970,14 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) newsp = regs->gpr[1]; newsp &= ~0xfUL; + /* + * Reenable the DABR before delivering the signal to + * user space. The DABR will have been cleared if it + * triggered inside the kernel. + */ + if (current->thread.dabr) + set_dabr(current->thread.dabr); + /* Whee! Actually deliver the signal. */ if (ka.sa.sa_flags & SA_SIGINFO) ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp); diff --git a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c index 772f0714a5b7d..7fbc68bbb7391 100644 --- a/arch/ppc64/mm/fault.c +++ b/arch/ppc64/mm/fault.c @@ -77,6 +77,28 @@ static int store_updates_sp(struct pt_regs *regs) return 0; } +static void do_dabr(struct pt_regs *regs, unsigned long error_code) +{ + siginfo_t info; + + if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, + 11, SIGSEGV) == NOTIFY_STOP) + return; + + if (debugger_dabr_match(regs)) + return; + + /* Clear the DABR */ + set_dabr(0); + + /* Deliver the signal to userspace */ + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_HWBKPT; + info.si_addr = (void __user *)regs->nip; + force_sig_info(SIGTRAP, &info, current); +} + /* * The error_code parameter is * - DSISR for a non-SLB data access fault, @@ -111,12 +133,9 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, if (!user_mode(regs) && (address >= TASK_SIZE)) return SIGSEGV; - if (error_code & DSISR_DABRMATCH) { - if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, - 11, SIGSEGV) == NOTIFY_STOP) - return 0; - if (debugger_dabr_match(regs)) - return 0; + if (error_code & DSISR_DABRMATCH) { + do_dabr(regs, error_code); + return 0; } if (in_atomic() || mm == NULL) { diff --git a/arch/ppc64/xmon/privinst.h b/arch/ppc64/xmon/privinst.h index 183c3e4002588..02eb40dac0b30 100644 --- a/arch/ppc64/xmon/privinst.h +++ b/arch/ppc64/xmon/privinst.h @@ -46,7 +46,6 @@ GSETSPR(287, pvr) GSETSPR(1008, hid0) GSETSPR(1009, hid1) GSETSPR(1010, iabr) -GSETSPR(1013, dabr) GSETSPR(1023, pir) static inline void store_inst(void *p) diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c index 45908b10acd34..74e63a886a69a 100644 --- a/arch/ppc64/xmon/xmon.c +++ b/arch/ppc64/xmon/xmon.c @@ -586,6 +586,8 @@ int xmon_dabr_match(struct pt_regs *regs) { if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) return 0; + if (dabr.enabled == 0) + return 0; xmon_core(regs, 0); return 1; } @@ -628,20 +630,6 @@ int xmon_fault_handler(struct pt_regs *regs) return 0; } -/* On systems with a hypervisor, we can't set the DABR - (data address breakpoint register) directly. */ -static void set_controlled_dabr(unsigned long val) -{ -#ifdef CONFIG_PPC_PSERIES - if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { - int rc = plpar_hcall_norets(H_SET_DABR, val); - if (rc != H_Success) - xmon_printf("Warning: setting DABR failed (%d)\n", rc); - } else -#endif - set_dabr(val); -} - static struct bpt *at_breakpoint(unsigned long pc) { int i; @@ -728,7 +716,7 @@ static void insert_bpts(void) static void insert_cpu_bpts(void) { if (dabr.enabled) - set_controlled_dabr(dabr.address | (dabr.enabled & 7)); + set_dabr(dabr.address | (dabr.enabled & 7)); if (iabr && cpu_has_feature(CPU_FTR_IABR)) set_iabr(iabr->address | (iabr->enabled & (BP_IABR|BP_IABR_TE))); @@ -756,7 +744,7 @@ static void remove_bpts(void) static void remove_cpu_bpts(void) { - set_controlled_dabr(0); + set_dabr(0); if (cpu_has_feature(CPU_FTR_IABR)) set_iabr(0); } diff --git a/include/asm-ppc64/hvcall.h b/include/asm-ppc64/hvcall.h index 4f668a4baff01..ab7c3cf24888c 100644 --- a/include/asm-ppc64/hvcall.h +++ b/include/asm-ppc64/hvcall.h @@ -56,6 +56,11 @@ #define H_PP1 (1UL<<(63-62)) #define H_PP2 (1UL<<(63-63)) +/* DABRX flags */ +#define H_DABRX_HYPERVISOR (1UL<<(63-61)) +#define H_DABRX_KERNEL (1UL<<(63-62)) +#define H_DABRX_USER (1UL<<(63-63)) + /* pSeries hypervisor opcodes */ #define H_REMOVE 0x04 #define H_ENTER 0x08 @@ -101,6 +106,7 @@ #define H_VIO_SIGNAL 0x104 #define H_SEND_CRQ 0x108 #define H_COPY_RDMA 0x110 +#define H_SET_XDABR 0x134 #define H_STUFF_TCE 0x138 #define H_PUT_TCE_INDIRECT 0x13C #define H_VTERM_PARTNER_INFO 0x150 diff --git a/include/asm-ppc64/plpar_wrappers.h b/include/asm-ppc64/plpar_wrappers.h index f4a5fb7d67c7c..72dd2449ee762 100644 --- a/include/asm-ppc64/plpar_wrappers.h +++ b/include/asm-ppc64/plpar_wrappers.h @@ -107,5 +107,14 @@ static inline long plpar_put_term_char(unsigned long termno, lbuf[1]); } +static inline long plpar_set_xdabr(unsigned long address, unsigned long flags) +{ + return plpar_hcall_norets(H_SET_XDABR, address, flags); +} + +static inline long plpar_set_dabr(unsigned long val) +{ + return plpar_hcall_norets(H_SET_DABR, val); +} #endif /* _PPC64_PLPAR_WRAPPERS_H */ diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h index 8bd7aa959385d..4146189006e32 100644 --- a/include/asm-ppc64/processor.h +++ b/include/asm-ppc64/processor.h @@ -433,6 +433,7 @@ struct thread_struct { unsigned long start_tb; /* Start purr when proc switched in */ unsigned long accum_tb; /* Total accumilated purr for process */ unsigned long vdso_base; /* base of the vDSO library */ + unsigned long dabr; /* Data address breakpoint register */ #ifdef CONFIG_ALTIVEC /* Complete AltiVec register set */ vector128 vr[32] __attribute((aligned(16))); diff --git a/include/asm-ppc64/ptrace-common.h b/include/asm-ppc64/ptrace-common.h index bd0f84c27bd0b..b1babb7296733 100644 --- a/include/asm-ppc64/ptrace-common.h +++ b/include/asm-ppc64/ptrace-common.h @@ -13,6 +13,7 @@ #define _PPC64_PTRACE_COMMON_H #include <linux/config.h> +#include <asm/system.h> /* * Set of msr bits that gdb can change on behalf of a process. @@ -141,4 +142,23 @@ static inline int set_vrregs(struct task_struct *task, } #endif +static inline int ptrace_set_debugreg(struct task_struct *task, + unsigned long addr, unsigned long data) +{ + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + return -EINVAL; + + /* The bottom 3 bits are flags */ + if ((data & ~0x7UL) >= TASK_SIZE) + return -EIO; + + /* Ensure translation is on */ + if (data && !(data & DABR_TRANSLATION)) + return -EIO; + + task->thread.dabr = data; + return 0; +} + #endif /* _PPC64_PTRACE_COMMON_H */ diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index c0396428cc3c0..375015c62f207 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -101,6 +101,9 @@ static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; } static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } #endif +extern int set_dabr(unsigned long dabr); +extern void _exception(int signr, struct pt_regs *regs, int code, + unsigned long addr); extern int fix_alignment(struct pt_regs *regs); extern void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig); -- GitLab From 26370322d8e3504db61cb8d438a9fca3b87ac0db Mon Sep 17 00:00:00 2001 From: Anton Blanchard <anton@samba.org> Date: Mon, 12 Sep 2005 13:12:11 +1000 Subject: [PATCH 483/563] [PATCH] ppc64: xics cleanup A few xics cleanups: - Make some things static. - Be more consistent with error printing - interrupts are unsigned, error values are signed. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org> --- arch/ppc64/kernel/xics.c | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c index d9dc6f28d0500..daf93885dcfab 100644 --- a/arch/ppc64/kernel/xics.c +++ b/arch/ppc64/kernel/xics.c @@ -38,7 +38,7 @@ static void xics_mask_and_ack_irq(unsigned int irq); static void xics_end_irq(unsigned int irq); static void xics_set_affinity(unsigned int irq_nr, cpumask_t cpumask); -struct hw_interrupt_type xics_pic = { +static struct hw_interrupt_type xics_pic = { .typename = " XICS ", .startup = xics_startup, .enable = xics_enable_irq, @@ -48,7 +48,7 @@ struct hw_interrupt_type xics_pic = { .set_affinity = xics_set_affinity }; -struct hw_interrupt_type xics_8259_pic = { +static struct hw_interrupt_type xics_8259_pic = { .typename = " XICS/8259", .ack = xics_mask_and_ack_irq, }; @@ -89,9 +89,8 @@ static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; static int xics_irq_8259_cascade = 0; static int xics_irq_8259_cascade_real = 0; static unsigned int default_server = 0xFF; -/* also referenced in smp.c... */ -unsigned int default_distrib_server = 0; -unsigned int interrupt_server_size = 8; +static unsigned int default_distrib_server = 0; +static unsigned int interrupt_server_size = 8; /* * XICS only has a single IPI, so encode the messages per CPU @@ -99,10 +98,10 @@ unsigned int interrupt_server_size = 8; struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; /* RTAS service tokens */ -int ibm_get_xive; -int ibm_set_xive; -int ibm_int_on; -int ibm_int_off; +static int ibm_get_xive; +static int ibm_set_xive; +static int ibm_int_on; +static int ibm_int_off; typedef struct { int (*xirr_info_get)(int cpu); @@ -284,16 +283,17 @@ static void xics_enable_irq(unsigned int virq) call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, DEFAULT_PRIORITY); if (call_status != 0) { - printk(KERN_ERR "xics_enable_irq: irq=%d: ibm_set_xive " - "returned %x\n", irq, call_status); + printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_set_xive " + "returned %d\n", irq, call_status); + printk("set_xive %x, server %x\n", ibm_set_xive, server); return; } /* Now unmask the interrupt (often a no-op) */ call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq); if (call_status != 0) { - printk(KERN_ERR "xics_enable_irq: irq=%d: ibm_int_on " - "returned %x\n", irq, call_status); + printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_int_on " + "returned %d\n", irq, call_status); return; } } @@ -308,8 +308,8 @@ static void xics_disable_real_irq(unsigned int irq) call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq); if (call_status != 0) { - printk(KERN_ERR "xics_disable_real_irq: irq=%d: " - "ibm_int_off returned %x\n", irq, call_status); + printk(KERN_ERR "xics_disable_real_irq: irq=%u: " + "ibm_int_off returned %d\n", irq, call_status); return; } @@ -317,8 +317,8 @@ static void xics_disable_real_irq(unsigned int irq) /* Have to set XIVE to 0xff to be able to remove a slot */ call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, 0xff); if (call_status != 0) { - printk(KERN_ERR "xics_disable_irq: irq=%d: ibm_set_xive(0xff)" - " returned %x\n", irq, call_status); + printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)" + " returned %d\n", irq, call_status); return; } } @@ -380,7 +380,7 @@ int xics_get_irq(struct pt_regs *regs) if (irq == NO_IRQ) irq = real_irq_to_virt_slowpath(vec); if (irq == NO_IRQ) { - printk(KERN_ERR "Interrupt %d (real) is invalid," + printk(KERN_ERR "Interrupt %u (real) is invalid," " disabling it.\n", vec); xics_disable_real_irq(vec); } else @@ -622,7 +622,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); if (status) { - printk(KERN_ERR "xics_set_affinity: irq=%d ibm,get-xive " + printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive " "returns %d\n", irq, status); return; } @@ -641,7 +641,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) irq, newmask, xics_status[1]); if (status) { - printk(KERN_ERR "xics_set_affinity: irq=%d ibm,set-xive " + printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " "returns %d\n", irq, status); return; } @@ -720,7 +720,7 @@ void xics_migrate_irqs_away(void) status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); if (status) { - printk(KERN_ERR "migrate_irqs_away: irq=%d " + printk(KERN_ERR "migrate_irqs_away: irq=%u " "ibm,get-xive returns %d\n", virq, status); goto unlock; @@ -734,7 +734,7 @@ void xics_migrate_irqs_away(void) if (xics_status[0] != get_hard_smp_processor_id(cpu)) goto unlock; - printk(KERN_WARNING "IRQ %d affinity broken off cpu %u\n", + printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", virq, cpu); /* Reset affinity to all cpus */ -- GitLab From 3238e9c9735cd5ebe30a59df1f8f5af2687344de Mon Sep 17 00:00:00 2001 From: Anton Blanchard <anton@samba.org> Date: Mon, 12 Sep 2005 13:14:26 +1000 Subject: [PATCH 484/563] [PATCH] ppc64: indent pci code Fix up some badly indented code. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org> --- arch/ppc64/kernel/iSeries_pci.c | 2 +- arch/ppc64/kernel/maple_pci.c | 56 +++++++++++++++--------------- arch/ppc64/kernel/pmac_pci.c | 60 ++++++++++++++++----------------- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c index 356e4fd9a94fe..fbc273c32bcc1 100644 --- a/arch/ppc64/kernel/iSeries_pci.c +++ b/arch/ppc64/kernel/iSeries_pci.c @@ -252,7 +252,7 @@ unsigned long __init find_and_init_phbs(void) phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), GFP_KERNEL); if (phb == NULL) return -ENOMEM; - pci_setup_pci_controller(phb); + pci_setup_pci_controller(phb); phb->pci_mem_offset = phb->local_number = bus; phb->first_busno = bus; diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c index 5a8b4d8c2dd62..1d297e0edfc0d 100644 --- a/arch/ppc64/kernel/maple_pci.c +++ b/arch/ppc64/kernel/maple_pci.c @@ -283,7 +283,7 @@ static void __init setup_u3_agp(struct pci_controller* hose) * the reg address cell, we shall fix that by killing struct * reg_property and using some accessor functions instead */ - hose->first_busno = 0xf0; + hose->first_busno = 0xf0; hose->last_busno = 0xff; hose->ops = &u3_agp_pci_ops; hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); @@ -315,24 +315,24 @@ static int __init add_bridge(struct device_node *dev) char* disp_name; int *bus_range; int primary = 1; - struct property *of_prop; + struct property *of_prop; DBG("Adding PCI host bridge %s\n", dev->full_name); - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", + dev->full_name); + } hose = alloc_bootmem(sizeof(struct pci_controller)); if (hose == NULL) return -ENOMEM; - pci_setup_pci_controller(hose); + pci_setup_pci_controller(hose); - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; + hose->arch_data = dev; + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; of_prop = alloc_bootmem(sizeof(struct property) + sizeof(hose->global_number)); @@ -346,25 +346,25 @@ static int __init add_bridge(struct device_node *dev) } disp_name = NULL; - if (device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose); - disp_name = "U3-AGP"; - primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose); - disp_name = "U3-HT"; - primary = 1; - } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pci_process_bridge_OF_ranges(hose, dev); + if (device_is_compatible(dev, "u3-agp")) { + setup_u3_agp(hose); + disp_name = "U3-AGP"; + primary = 0; + } else if (device_is_compatible(dev, "u3-ht")) { + setup_u3_ht(hose); + disp_name = "U3-HT"; + primary = 1; + } + printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", + disp_name, hose->first_busno, hose->last_busno); + + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pci_process_bridge_OF_ranges(hose, dev); pci_setup_phb_io(hose, primary); - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); + /* Fixup "bus-range" OF property */ + fixup_bus_range(dev); return 0; } diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c index d37bff2d7d40c..dc40a0cad0b47 100644 --- a/arch/ppc64/kernel/pmac_pci.c +++ b/arch/ppc64/kernel/pmac_pci.c @@ -388,7 +388,7 @@ static void __init setup_u3_agp(struct pci_controller* hose) * the reg address cell, we shall fix that by killing struct * reg_property and using some accessor functions instead */ - hose->first_busno = 0xf0; + hose->first_busno = 0xf0; hose->last_busno = 0xff; has_uninorth = 1; hose->ops = ¯isc_pci_ops; @@ -473,7 +473,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) continue; } cur++; - DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", + DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", cur-1, res->start - 1, cur, res->end + 1); hose->mem_resources[cur].name = np->full_name; hose->mem_resources[cur].flags = IORESOURCE_MEM; @@ -603,24 +603,24 @@ static int __init add_bridge(struct device_node *dev) char* disp_name; int *bus_range; int primary = 1; - struct property *of_prop; + struct property *of_prop; DBG("Adding PCI host bridge %s\n", dev->full_name); - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } + bus_range = (int *) get_property(dev, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", + dev->full_name); + } hose = alloc_bootmem(sizeof(struct pci_controller)); if (hose == NULL) return -ENOMEM; - pci_setup_pci_controller(hose); + pci_setup_pci_controller(hose); - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; + hose->arch_data = dev; + hose->first_busno = bus_range ? bus_range[0] : 0; + hose->last_busno = bus_range ? bus_range[1] : 0xff; of_prop = alloc_bootmem(sizeof(struct property) + sizeof(hose->global_number)); @@ -634,24 +634,24 @@ static int __init add_bridge(struct device_node *dev) } disp_name = NULL; - if (device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose); - disp_name = "U3-AGP"; - primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose); - disp_name = "U3-HT"; - primary = 1; - } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pmac_process_bridge_OF_ranges(hose, dev, primary); - - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); + if (device_is_compatible(dev, "u3-agp")) { + setup_u3_agp(hose); + disp_name = "U3-AGP"; + primary = 0; + } else if (device_is_compatible(dev, "u3-ht")) { + setup_u3_ht(hose); + disp_name = "U3-HT"; + primary = 1; + } + printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", + disp_name, hose->first_busno, hose->last_busno); + + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + pmac_process_bridge_OF_ranges(hose, dev, primary); + + /* Fixup "bus-range" OF property */ + fixup_bus_range(dev); return 0; } -- GitLab From 1ed2fd2d3a8d18f184ba2d06e0f03bff773f28ab Mon Sep 17 00:00:00 2001 From: Anton Blanchard <anton@samba.org> Date: Mon, 12 Sep 2005 13:17:27 +1000 Subject: [PATCH 485/563] [PATCH] ppc64: Fix for missing start-cpu rtas token If the rtas start-cpu token doesnt exist then presume the cpu is already spinning. If it isnt we will catch it later on when the cpu doesnt respond. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org> --- arch/ppc64/kernel/pSeries_smp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index 79c7f32236658..d2c7e2c4733b7 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c @@ -272,6 +272,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) unsigned long start_here = __pa((u32)*((unsigned long *) pSeries_secondary_smp_init)); unsigned int pcpu; + int start_cpu; if (cpu_isset(lcpu, of_spin_map)) /* Already started by OF and sitting in spin loop */ @@ -282,12 +283,20 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) /* Fixup atomic count: it exited inside IRQ handler. */ paca[lcpu].__current->thread_info->preempt_count = 0; - status = rtas_call(rtas_token("start-cpu"), 3, 1, NULL, - pcpu, start_here, lcpu); + /* + * If the RTAS start-cpu token does not exist then presume the + * cpu is already spinning. + */ + start_cpu = rtas_token("start-cpu"); + if (start_cpu == RTAS_UNKNOWN_SERVICE) + return 1; + + status = rtas_call(start_cpu, 3, 1, NULL, pcpu, start_here, lcpu); if (status != 0) { printk(KERN_ERR "start-cpu failed: %i\n", status); return 0; } + return 1; } -- GitLab From 2d909d08db7655a53f3afb31c7627c5c8c87142a Mon Sep 17 00:00:00 2001 From: Anton Blanchard <anton@samba.org> Date: Mon, 12 Sep 2005 13:19:51 +1000 Subject: [PATCH 486/563] [PATCH] ppc64: Remove unused code ppc64_attention_msg and ppc64_dump_msg are not used so remove them. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org> --- arch/ppc64/kernel/setup.c | 16 ---------------- include/asm-ppc64/machdep.h | 4 ---- 2 files changed, 20 deletions(-) diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index bfa8791c9807f..5ac48bd64891f 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -1064,8 +1064,6 @@ void __init setup_arch(char **cmdline_p) #define PPC64_LINUX_FUNCTION 0x0f000000 #define PPC64_IPL_MESSAGE 0xc0000000 #define PPC64_TERM_MESSAGE 0xb0000000 -#define PPC64_ATTN_MESSAGE 0xa0000000 -#define PPC64_DUMP_MESSAGE 0xd0000000 static void ppc64_do_msg(unsigned int src, const char *msg) { @@ -1093,20 +1091,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) printk("[terminate]%04x %s\n", src, msg); } -/* Print something that needs attention (device error, etc) */ -void ppc64_attention_msg(unsigned int src, const char *msg) -{ - ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg); - printk("[attention]%04x %s\n", src, msg); -} - -/* Print a dump progress message. */ -void ppc64_dump_msg(unsigned int src, const char *msg) -{ - ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg); - printk("[dump]%04x %s\n", src, msg); -} - /* This should only be called on processor 0 during calibrate decr */ void __init setup_default_decr(void) { diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h index 7b25738c111f1..8027160ec96d0 100644 --- a/include/asm-ppc64/machdep.h +++ b/include/asm-ppc64/machdep.h @@ -174,10 +174,6 @@ extern sys_ctrler_t sys_ctrler; void ppc64_boot_msg(unsigned int src, const char *msg); /* Print a termination message (print only -- does not stop the kernel) */ void ppc64_terminate_msg(unsigned int src, const char *msg); -/* Print something that needs attention (device error, etc) */ -void ppc64_attention_msg(unsigned int src, const char *msg); -/* Print a dump progress message. */ -void ppc64_dump_msg(unsigned int src, const char *msg); static inline void log_error(char *buf, unsigned int err_type, int fatal) { -- GitLab From c3ff8ec31c1249d268cd11390649768a12bec1b9 Mon Sep 17 00:00:00 2001 From: Roland McGrath <roland@redhat.com> Date: Sun, 11 Sep 2005 01:44:45 -0700 Subject: [PATCH 487/563] [PATCH] i386: Don't miss pending signals returning to user mode after signal processing Signed-off-by: Roland McGrath <roland@redhat.com> Acked-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/kernel/entry.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 3aad03839660d..9e24f7b207ee1 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -319,7 +319,7 @@ work_notifysig: # deal with pending signals and # vm86-space xorl %edx, %edx call do_notify_resume - jmp restore_all + jmp resume_userspace ALIGN work_notifysig_v86: @@ -329,7 +329,7 @@ work_notifysig_v86: movl %eax, %esp xorl %edx, %edx call do_notify_resume - jmp restore_all + jmp resume_userspace # perform syscall exit tracing ALIGN -- GitLab From 1df5c10a5b40d1ad747e3de3caf28764153c5c8e Mon Sep 17 00:00:00 2001 From: Linus Torvalds <torvalds@g5.osdl.org> Date: Mon, 12 Sep 2005 07:59:21 -0700 Subject: [PATCH 488/563] Mark ia64-specific MCA/INIT scheduler hooks as dangerous ..and only enable them for ia64. The functions are only valid when the whole system has been totally stopped and no scheduler activity is ongoing on any CPU, and interrupts are globally disabled. In other words, they aren't useful for anything else. So make sure that nobody can use them by mistake. Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- kernel/sched.c | 70 +++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index e9ff04a9b56df..81b3a96ed2d09 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3576,32 +3576,6 @@ task_t *idle_task(int cpu) return cpu_rq(cpu)->idle; } -/** - * curr_task - return the current task for a given cpu. - * @cpu: the processor in question. - */ -task_t *curr_task(int cpu) -{ - return cpu_curr(cpu); -} - -/** - * set_curr_task - set the current task for a given cpu. - * @cpu: the processor in question. - * @p: the task pointer to set. - * - * Description: This function must only be used when non-maskable interrupts - * are serviced on a separate stack. It allows the architecture to switch the - * notion of the current task on a cpu in a non-blocking manner. This function - * must be called with interrupts disabled, the caller must save the original - * value of the current task (see curr_task() above) and restore that value - * before reenabling interrupts. - */ -void set_curr_task(int cpu, task_t *p) -{ - cpu_curr(cpu) = p; -} - /** * find_process_by_pid - find a process with a matching PID value. * @pid: the pid in question. @@ -5628,3 +5602,47 @@ void normalize_rt_tasks(void) } #endif /* CONFIG_MAGIC_SYSRQ */ + +#ifdef CONFIG_IA64 +/* + * These functions are only useful for the IA64 MCA handling. + * + * They can only be called when the whole system has been + * stopped - every CPU needs to be quiescent, and no scheduling + * activity can take place. Using them for anything else would + * be a serious bug, and as a result, they aren't even visible + * under any other configuration. + */ + +/** + * curr_task - return the current task for a given cpu. + * @cpu: the processor in question. + * + * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED! + */ +task_t *curr_task(int cpu) +{ + return cpu_curr(cpu); +} + +/** + * set_curr_task - set the current task for a given cpu. + * @cpu: the processor in question. + * @p: the task pointer to set. + * + * Description: This function must only be used when non-maskable interrupts + * are serviced on a separate stack. It allows the architecture to switch the + * notion of the current task on a cpu in a non-blocking manner. This function + * must be called with all CPU's synchronized, and interrupts disabled, the + * and caller must save the original value of the current task (see + * curr_task() above) and restore that value before reenabling interrupts and + * re-starting the system. + * + * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED! + */ +void set_curr_task(int cpu, task_t *p) +{ + cpu_curr(cpu) = p; +} + +#endif -- GitLab From f24ec7f6c6278c0ea4c00efe96d50b1e66796c44 Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Date: Mon, 12 Sep 2005 17:12:43 +0400 Subject: [PATCH 489/563] [PATCH] crc16: remove w1 specific comments. Remove w1 comments from crc16.h and move specific constants into w1_ds2433.c where they are used. Replace %d with %zd. Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- drivers/w1/w1_ds2433.c | 6 +++++- include/linux/crc16.h | 16 +--------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/w1/w1_ds2433.c b/drivers/w1/w1_ds2433.c index b7c24b34d270d..279e0e0363d6a 100644 --- a/drivers/w1/w1_ds2433.c +++ b/drivers/w1/w1_ds2433.c @@ -15,6 +15,10 @@ #include <linux/delay.h> #ifdef CONFIG_W1_F23_CRC #include <linux/crc16.h> + +#define CRC16_INIT 0 +#define CRC16_VALID 0xb001 + #endif #include "w1.h" @@ -214,7 +218,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off, #ifdef CONFIG_W1_F23_CRC /* can only write full blocks in cached mode */ if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) { - dev_err(&sl->dev, "invalid offset/count off=%d cnt=%d\n", + dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n", (int)off, count); return -EINVAL; } diff --git a/include/linux/crc16.h b/include/linux/crc16.h index bdedf825b04a5..9443c084f8811 100644 --- a/include/linux/crc16.h +++ b/include/linux/crc16.h @@ -1,22 +1,11 @@ /* * crc16.h - CRC-16 routine * - * Implements the standard CRC-16, as used with 1-wire devices: + * Implements the standard CRC-16: * Width 16 * Poly 0x8005 (x^16 + x^15 + x^2 + 1) * Init 0 * - * For 1-wire devices, the CRC is stored inverted, LSB-first - * - * Example buffer with the CRC attached: - * 31 32 33 34 35 36 37 38 39 C2 44 - * - * The CRC over a buffer with the CRC attached is 0xB001. - * So, if (crc16(0, buf, size) == 0xB001) then the buffer is valid. - * - * Refer to "Application Note 937: Book of iButton Standards" for details. - * http://www.maxim-ic.com/appnotes.cfm/appnote_number/937 - * * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com> * * This source code is licensed under the GNU General Public License, @@ -28,9 +17,6 @@ #include <linux/types.h> -#define CRC16_INIT 0 -#define CRC16_VALID 0xb001 - extern u16 const crc16_table[256]; extern u16 crc16(u16 crc, const u8 *buffer, size_t len); -- GitLab From b3426599af9524104be6938bcb1fcaab314781c7 Mon Sep 17 00:00:00 2001 From: Paul Jackson <pj@sgi.com> Date: Mon, 12 Sep 2005 04:30:30 -0700 Subject: [PATCH 490/563] [PATCH] cpuset semaphore depth check optimize Optimize the deadlock avoidance check on the global cpuset semaphore cpuset_sem. Instead of adding a depth counter to the task struct of each task, rather just two words are enough, one to store the depth and the other the current cpuset_sem holder. Thanks to Nikita Danilov for the idea. Signed-off-by: Paul Jackson <pj@sgi.com> [ We may want to change this further, but at least it's now a totally internal decision to the cpusets code ] Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/sched.h | 1 - kernel/cpuset.c | 13 +++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index ed3bb19d13372..38c8654aaa96b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -785,7 +785,6 @@ struct task_struct { short il_next; #endif #ifdef CONFIG_CPUSETS - short cpuset_sem_nest_depth; struct cpuset *cpuset; nodemask_t mems_allowed; int cpuset_mems_generation; diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 407b5f0a8c8ee..79866bc6b3a15 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -180,6 +180,8 @@ static struct super_block *cpuset_sb = NULL; */ static DECLARE_MUTEX(cpuset_sem); +static struct task_struct *cpuset_sem_owner; +static int cpuset_sem_depth; /* * The global cpuset semaphore cpuset_sem can be needed by the @@ -200,16 +202,19 @@ static DECLARE_MUTEX(cpuset_sem); static inline void cpuset_down(struct semaphore *psem) { - if (current->cpuset_sem_nest_depth == 0) + if (cpuset_sem_owner != current) { down(psem); - current->cpuset_sem_nest_depth++; + cpuset_sem_owner = current; + } + cpuset_sem_depth++; } static inline void cpuset_up(struct semaphore *psem) { - current->cpuset_sem_nest_depth--; - if (current->cpuset_sem_nest_depth == 0) + if (--cpuset_sem_depth == 0) { + cpuset_sem_owner = NULL; up(psem); + } } /* -- GitLab From f343bb4cd7cc76d49d72415c8b867b1073d3c6db Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:23 +0200 Subject: [PATCH 491/563] [PATCH] x86{-64}: Remove old hack that disabled mmconfig support on AMD systems. Now that Greg implemented MCFG/_SEG support this shouldn't be needed anymore Cc: gregkh@suse.de Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/pci/mmconfig.c | 7 ------- arch/x86_64/pci/mmconfig.c | 7 ------- 2 files changed, 14 deletions(-) diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index 60f0e7a1162aa..dfbf80cff8346 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -127,13 +127,6 @@ static int __init pci_mmcfg_init(void) (pci_mmcfg_config[0].base_address == 0)) goto out; - /* Kludge for now. Don't use mmconfig on AMD systems because - those have some busses where mmconfig doesn't work, - and we don't parse ACPI MCFG well enough to handle that. - Remove when proper handling is added. */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) - goto out; - printk(KERN_INFO "PCI: Using MMCONFIG\n"); raw_pci_ops = &pci_mmcfg; pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index 657e88aa09022..a0838c4a94e4c 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c @@ -111,13 +111,6 @@ static int __init pci_mmcfg_init(void) (pci_mmcfg_config[0].base_address == 0)) return 0; - /* Kludge for now. Don't use mmconfig on AMD systems because - those have some busses where mmconfig doesn't work, - and we don't parse ACPI MCFG well enough to handle that. - Remove when proper handling is added. */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) - return 0; - /* RED-PEN i386 doesn't do _nocache right now */ pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL); if (pci_mmcfg_virt == NULL) { -- GitLab From affc9b844905f749064752faebb1af699f2d13bf Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:23 +0200 Subject: [PATCH 492/563] [PATCH] x86-64: Update defconfig Allow diskless booting. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/defconfig | 65 ++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig index bf57e2362bf4c..f8db7e500fbfd 100644 --- a/arch/x86_64/defconfig +++ b/arch/x86_64/defconfig @@ -1,11 +1,12 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc6-git3 -# Fri Aug 12 16:40:34 2005 +# Linux kernel version: 2.6.13-git11 +# Mon Sep 12 16:16:16 2005 # CONFIG_X86_64=y CONFIG_64BIT=y CONFIG_X86=y +CONFIG_SEMAPHORE_SLEEPERS=y CONFIG_MMU=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y @@ -13,6 +14,7 @@ CONFIG_X86_CMPXCHG=y CONFIG_EARLY_PRINTK=y CONFIG_GENERIC_ISA_DMA=y CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y # # Code maturity level options @@ -26,6 +28,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -37,6 +40,7 @@ CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y @@ -102,6 +106,7 @@ CONFIG_DISCONTIGMEM_MANUAL=y CONFIG_DISCONTIGMEM=y CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_NEED_MULTIPLE_NODES=y +# CONFIG_SPARSEMEM_STATIC is not set CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y CONFIG_HAVE_DEC_LOCK=y CONFIG_NR_CPUS=32 @@ -122,6 +127,7 @@ CONFIG_HZ=250 CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_ISA_DMA_API=y +CONFIG_GENERIC_PENDING_IRQ=y # # Power management options @@ -194,7 +200,6 @@ CONFIG_UNORDERED_IO=y # CONFIG_PCIEPORTBUS is not set CONFIG_PCI_MSI=y # CONFIG_PCI_LEGACY_PROC is not set -# CONFIG_PCI_NAMES is not set # CONFIG_PCI_DEBUG is not set # @@ -234,7 +239,10 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_FIB_HASH=y -# CONFIG_IP_PNP is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set @@ -244,8 +252,8 @@ CONFIG_IP_FIB_HASH=y # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -CONFIG_IP_TCPDIAG_IPV6=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y CONFIG_IPV6=y @@ -257,6 +265,11 @@ CONFIG_IPV6=y # CONFIG_IPV6_TUNNEL is not set # CONFIG_NETFILTER is not set +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + # # SCTP Configuration (EXPERIMENTAL) # @@ -280,9 +293,11 @@ CONFIG_IPV6=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETFILTER_NETLINK is not set # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set +# CONFIG_IEEE80211 is not set # # Device Drivers @@ -329,7 +344,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" CONFIG_LBD=y # CONFIG_CDROM_PKTCDVD is not set @@ -409,6 +423,7 @@ CONFIG_IDEDMA_AUTO=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y # CONFIG_SCSI_PROC_FS is not set @@ -432,7 +447,7 @@ CONFIG_BLK_DEV_SD=y # # SCSI Transport Attributes # -# CONFIG_SCSI_SPI_ATTRS is not set +CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set @@ -458,6 +473,7 @@ CONFIG_SCSI_SATA=y # CONFIG_SCSI_SATA_AHCI is not set # CONFIG_SCSI_SATA_SVW is not set CONFIG_SCSI_ATA_PIIX=y +# CONFIG_SCSI_SATA_MV is not set # CONFIG_SCSI_SATA_NV is not set # CONFIG_SCSI_SATA_PROMISE is not set # CONFIG_SCSI_SATA_QSTOR is not set @@ -536,6 +552,11 @@ CONFIG_TUN=y # # CONFIG_ARCNET is not set +# +# PHY device support +# +# CONFIG_PHYLIB is not set + # # Ethernet (10 or 100Mbit) # @@ -586,6 +607,7 @@ CONFIG_E1000=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set @@ -595,6 +617,7 @@ CONFIG_TIGON3=y # # Ethernet (10000 Mbit) # +# CONFIG_CHELSIO_T1 is not set # CONFIG_IXGB is not set CONFIG_S2IO=m # CONFIG_S2IO_NAPI is not set @@ -749,7 +772,6 @@ CONFIG_MAX_RAW_DEVS=256 # I2C support # # CONFIG_I2C is not set -# CONFIG_I2C_SENSOR is not set # # Dallas's 1-wire bus @@ -760,6 +782,7 @@ CONFIG_MAX_RAW_DEVS=256 # Hardware Monitoring support # CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set # CONFIG_HWMON_DEBUG_CHIP is not set # @@ -767,6 +790,10 @@ CONFIG_HWMON=y # # CONFIG_IBM_ASM is not set +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -858,9 +885,8 @@ CONFIG_USB_UHCI_HCD=y # # USB Device Class drivers # -# CONFIG_USB_AUDIO is not set +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set # CONFIG_USB_BLUETOOTH_TTY is not set -# CONFIG_USB_MIDI is not set # CONFIG_USB_ACM is not set CONFIG_USB_PRINTER=y @@ -877,6 +903,7 @@ CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_SDDR09 is not set # CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set # # USB Input Devices @@ -893,6 +920,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_MTOUCH is not set # CONFIG_USB_ITMTOUCH is not set # CONFIG_USB_EGALAX is not set +# CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set # CONFIG_USB_KEYSPAN_REMOTE is not set @@ -976,6 +1004,8 @@ CONFIG_USB_MON=y # Firmware Drivers # # CONFIG_EDD is not set +# CONFIG_DELL_RBU is not set +CONFIG_DCDBAS=m # # File systems @@ -1000,10 +1030,6 @@ CONFIG_REISERFS_FS_POSIX_ACL=y # CONFIG_REISERFS_FS_SECURITY is not set # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y - -# -# XFS support -# # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -1012,6 +1038,7 @@ CONFIG_INOTIFY=y CONFIG_DNOTIFY=y CONFIG_AUTOFS_FS=y # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -1037,12 +1064,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set CONFIG_HUGETLBFS=y CONFIG_HUGETLB_PAGE=y CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -1074,6 +1100,7 @@ CONFIG_NFSD_V3=y # CONFIG_NFSD_V3_ACL is not set # CONFIG_NFSD_V4 is not set CONFIG_NFSD_TCP=y +CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y @@ -1086,6 +1113,7 @@ CONFIG_SUNRPC=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -1150,6 +1178,7 @@ CONFIG_OPROFILE=y CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y CONFIG_LOG_BUF_SHIFT=18 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set @@ -1157,6 +1186,7 @@ CONFIG_LOG_BUF_SHIFT=18 # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_FS=y +# CONFIG_FRAME_POINTER is not set CONFIG_INIT_DEBUG=y # CONFIG_IOMMU_DEBUG is not set CONFIG_KPROBES=y @@ -1180,5 +1210,6 @@ CONFIG_KPROBES=y # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set -- GitLab From c1507eb2ee845b123ace751bec9c992a1937872c Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:23 +0200 Subject: [PATCH 493/563] [PATCH] x86-64: Remove apic_write_around from smpboot.c We don't do workarounds for ancient hardware bugs. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/smpboot.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 4fb34b5cb1f96..d4b63281c0f5c 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -540,8 +540,8 @@ static void inquire_remote_apic(int apicid) */ apic_wait_icr_idle(); - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); - apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]); + apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); + apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]); timeout = 0; do { @@ -574,12 +574,12 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta /* * Turn INIT on target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); + apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* * Send IPI */ - apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT + apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT); Dprintk("Waiting for send to finish...\n"); @@ -595,10 +595,10 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta Dprintk("Deasserting INIT.\n"); /* Target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); + apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* Send IPI */ - apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); + apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); Dprintk("Waiting for send to finish...\n"); timeout = 0; @@ -640,12 +640,11 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta */ /* Target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); + apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* Boot on the stack */ /* Kick the second */ - apic_write_around(APIC_ICR, APIC_DM_STARTUP - | (start_rip >> 12)); + apic_write(APIC_ICR, APIC_DM_STARTUP | (start_rip >> 12)); /* * Give the other CPU some time to accept the IPI. -- GitLab From eddfb4ed290383abf912630fa8dac5acf65c9e55 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:23 +0200 Subject: [PATCH 494/563] [PATCH] x86-64: Remove obsolete APIC "write around" bug workaround No x86-64 chipset has this bug Generated code doesn't change because it was always disabled. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/genapic_cluster.c | 4 ++-- arch/x86_64/kernel/genapic_flat.c | 8 ++++---- include/asm-x86_64/ipi.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/x86_64/kernel/genapic_cluster.c b/arch/x86_64/kernel/genapic_cluster.c index f6523dd1bc093..a472d62f899a8 100644 --- a/arch/x86_64/kernel/genapic_cluster.c +++ b/arch/x86_64/kernel/genapic_cluster.c @@ -51,10 +51,10 @@ static void cluster_init_apic_ldr(void) count = 3; id = my_cluster | (1UL << count); x86_cpu_to_log_apicid[smp_processor_id()] = id; - apic_write_around(APIC_DFR, APIC_DFR_CLUSTER); + apic_write(APIC_DFR, APIC_DFR_CLUSTER); val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; val |= SET_APIC_LOGICAL_ID(id); - apic_write_around(APIC_LDR, val); + apic_write(APIC_LDR, val); } /* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */ diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c index 6d57da96bf8c7..8c6028a0f322f 100644 --- a/arch/x86_64/kernel/genapic_flat.c +++ b/arch/x86_64/kernel/genapic_flat.c @@ -38,10 +38,10 @@ static void flat_init_apic_ldr(void) num = smp_processor_id(); id = 1UL << num; x86_cpu_to_log_apicid[num] = id; - apic_write_around(APIC_DFR, APIC_DFR_FLAT); + apic_write(APIC_DFR, APIC_DFR_FLAT); val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; val |= SET_APIC_LOGICAL_ID(id); - apic_write_around(APIC_LDR, val); + apic_write(APIC_LDR, val); } static void flat_send_IPI_mask(cpumask_t cpumask, int vector) @@ -62,7 +62,7 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector) * prepare target chip field */ cfg = __prepare_ICR2(mask); - apic_write_around(APIC_ICR2, cfg); + apic_write(APIC_ICR2, cfg); /* * program the ICR @@ -72,7 +72,7 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector) /* * Send the IPI. The write to APIC_ICR fires this off. */ - apic_write_around(APIC_ICR, cfg); + apic_write(APIC_ICR, cfg); local_irq_restore(flags); } diff --git a/include/asm-x86_64/ipi.h b/include/asm-x86_64/ipi.h index 5e166b9d3bdeb..7ba668f43c599 100644 --- a/include/asm-x86_64/ipi.h +++ b/include/asm-x86_64/ipi.h @@ -66,7 +66,7 @@ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector, unsign /* * Send the IPI. The write to APIC_ICR fires this off. */ - apic_write_around(APIC_ICR, cfg); + apic_write(APIC_ICR, cfg); } @@ -92,7 +92,7 @@ static inline void send_IPI_mask_sequence(cpumask_t mask, int vector) * prepare target chip field */ cfg = __prepare_ICR2(x86_cpu_to_apicid[query_cpu]); - apic_write_around(APIC_ICR2, cfg); + apic_write(APIC_ICR2, cfg); /* * program the ICR @@ -102,7 +102,7 @@ static inline void send_IPI_mask_sequence(cpumask_t mask, int vector) /* * Send the IPI. The write to APIC_ICR fires this off. */ - apic_write_around(APIC_ICR, cfg); + apic_write(APIC_ICR, cfg); } local_irq_restore(flags); } -- GitLab From 61c11341ed798db9b99b30c1711c1cf458457806 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:23 +0200 Subject: [PATCH 495/563] [PATCH] x86-64: Remove esr disable hack in APIC code This was just needed for the Numasaurus, which fortunately doesn't support x86-64 CPUs. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/apic.c | 21 +-------------------- include/asm-x86_64/apic.h | 1 - 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 375d369570ca3..9af0cc3e2ccce 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -325,14 +325,6 @@ void __cpuinit setup_local_APIC (void) { unsigned int value, ver, maxlvt; - /* Pound the ESR really hard over the head with a big hammer - mbligh */ - if (esr_disable) { - apic_write(APIC_ESR, 0); - apic_write(APIC_ESR, 0); - apic_write(APIC_ESR, 0); - apic_write(APIC_ESR, 0); - } - value = apic_read(APIC_LVR); ver = GET_APIC_VERSION(value); @@ -434,7 +426,7 @@ void __cpuinit setup_local_APIC (void) value |= APIC_LVT_LEVEL_TRIGGER; apic_write_around(APIC_LVT1, value); - if (APIC_INTEGRATED(ver) && !esr_disable) { /* !82489DX */ + { unsigned oldvalue; maxlvt = get_maxlvt(); if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ @@ -452,17 +444,6 @@ void __cpuinit setup_local_APIC (void) apic_printk(APIC_VERBOSE, "ESR value after enabling vector: %08x, after %08x\n", oldvalue, value); - } else { - if (esr_disable) - /* - * Something untraceble is creating bad interrupts on - * secondary quads ... for the moment, just leave the - * ESR disabled - we can't do anything useful with the - * errors anyway - mbligh - */ - apic_printk(APIC_DEBUG, "Leaving ESR disabled.\n"); - else - apic_printk(APIC_DEBUG, "No ESR for 82489DX.\n"); } nmi_watchdog_default(); diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h index 16ec82e16b21a..1559d78894acc 100644 --- a/include/asm-x86_64/apic.h +++ b/include/asm-x86_64/apic.h @@ -111,7 +111,6 @@ extern unsigned int nmi_watchdog; #endif /* CONFIG_X86_LOCAL_APIC */ -#define esr_disable 0 extern unsigned boot_cpu_id; #endif /* __ASM_APIC_H */ -- GitLab From 5a40b7c2abdedcf53c9a6ee790991acfcef5b6c7 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 496/563] [PATCH] x86-64: Remove code for outdated APICs No x86-64 chipset has these APICs. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/apic.c | 15 ++------------- arch/x86_64/kernel/io_apic.c | 20 +++++++------------- arch/x86_64/kernel/smpboot.c | 11 +---------- 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 9af0cc3e2ccce..fc84bea42fd41 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -109,11 +109,8 @@ void clear_local_APIC(void) if (maxlvt >= 4) apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); v = GET_APIC_VERSION(apic_read(APIC_LVR)); - if (APIC_INTEGRATED(v)) { /* !82489DX */ - if (maxlvt > 3) /* Due to Pentium errata 3AP and 11AP. */ - apic_write(APIC_ESR, 0); - apic_read(APIC_ESR); - } + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); } void __init connect_bsp_APIC(void) @@ -316,8 +313,6 @@ void __init init_bsp_APIC(void) */ apic_write_around(APIC_LVT0, APIC_DM_EXTINT); value = APIC_DM_NMI; - if (!APIC_INTEGRATED(ver)) /* 82489DX */ - value |= APIC_LVT_LEVEL_TRIGGER; apic_write_around(APIC_LVT1, value); } @@ -422,15 +417,11 @@ void __cpuinit setup_local_APIC (void) value = APIC_DM_NMI; else value = APIC_DM_NMI | APIC_LVT_MASKED; - if (!APIC_INTEGRATED(ver)) /* 82489DX */ - value |= APIC_LVT_LEVEL_TRIGGER; apic_write_around(APIC_LVT1, value); { unsigned oldvalue; maxlvt = get_maxlvt(); - if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ - apic_write(APIC_ESR, 0); oldvalue = apic_read(APIC_ESR); value = ERROR_APIC_VECTOR; // enables sending errors apic_write_around(APIC_LVTERR, value); @@ -674,8 +665,6 @@ static void __setup_APIC_LVTT(unsigned int clocks) ver = GET_APIC_VERSION(apic_read(APIC_LVR)); lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; - if (!APIC_INTEGRATED(ver)) - lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV); apic_write_around(APIC_LVTT, lvtt_value); /* diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 5f1529be12374..0645dc835527d 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1022,13 +1022,11 @@ void __apicdebuginit print_local_APIC(void * dummy) v = apic_read(APIC_TASKPRI); printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); - if (APIC_INTEGRATED(ver)) { /* !82489DX */ - v = apic_read(APIC_ARBPRI); - printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, - v & APIC_ARBPRI_MASK); - v = apic_read(APIC_PROCPRI); - printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v); - } + v = apic_read(APIC_ARBPRI); + printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, + v & APIC_ARBPRI_MASK); + v = apic_read(APIC_PROCPRI); + printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v); v = apic_read(APIC_EOI); printk(KERN_DEBUG "... APIC EOI: %08x\n", v); @@ -1048,12 +1046,8 @@ void __apicdebuginit print_local_APIC(void * dummy) printk(KERN_DEBUG "... APIC IRR field:\n"); print_APIC_bitfield(APIC_IRR); - if (APIC_INTEGRATED(ver)) { /* !82489DX */ - if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ - apic_write(APIC_ESR, 0); - v = apic_read(APIC_ESR); - printk(KERN_DEBUG "... APIC ESR: %08x\n", v); - } + v = apic_read(APIC_ESR); + printk(KERN_DEBUG "... APIC ESR: %08x\n", v); v = apic_read(APIC_ICR); printk(KERN_DEBUG "... APIC ICR: %08x\n", v); diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index d4b63281c0f5c..4efe36fe99aa9 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -610,16 +610,7 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta atomic_set(&init_deasserted, 1); - /* - * Should we send STARTUP IPIs ? - * - * Determine this based on the APIC version. - * If we don't have an integrated APIC, don't send the STARTUP IPIs. - */ - if (APIC_INTEGRATED(apic_version[phys_apicid])) - num_starts = 2; - else - num_starts = 0; + num_starts = 2; /* * Run STARTUP IPI loop. -- GitLab From 70556463487f33bc6728a7596b97f86b811aad22 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 497/563] [PATCH] x86-64: Use largest APIC number, not number of CPUs to decide on physflat mode Handles case where BIOS gives CPUs very large APIC numbers correctly. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/genapic.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c index b1c144f731498..f3159a496e39c 100644 --- a/arch/x86_64/kernel/genapic.c +++ b/arch/x86_64/kernel/genapic.c @@ -45,7 +45,7 @@ void __init clustered_apic_check(void) u8 clusters, max_cluster; u8 id; u8 cluster_cnt[NUM_APIC_CLUSTERS]; - int num_cpus = 0; + int max_apic = 0; #if defined(CONFIG_ACPI) /* @@ -64,7 +64,8 @@ void __init clustered_apic_check(void) id = bios_cpu_apicid[i]; if (id == BAD_APICID) continue; - num_cpus++; + if (id > max_apic) + max_apic = id; cluster_cnt[APIC_CLUSTERID(id)]++; } @@ -79,7 +80,7 @@ void __init clustered_apic_check(void) we have ACPI platform support for CPU hotplug we should detect hotplug capablity from ACPI tables and only do this when really needed. -AK */ - if (num_cpus <= 8) + if (max_apic <= 8) genapic = &apic_flat; #endif goto print; -- GitLab From b4452218c4b7a579056d439b73a668b71654c137 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 498/563] [PATCH] x86-64: Enable interrupts during delay calibration on APs We used to disable them to work around a bug, but that is not needed anymore. Keeping them enabled avoids the NMI watchdog triggering in some cases. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/smpboot.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 4efe36fe99aa9..277ce5e91e04d 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -413,8 +413,13 @@ void __cpuinit smp_callin(void) /* * Get our bogomips. + * + * Need to enable IRQs because it can take longer and then + * the NMI watchdog might kill us. */ + local_irq_enable(); calibrate_delay(); + local_irq_disable(); Dprintk("Stack at about %p\n",&cpuid); disable_APIC_timer(); -- GitLab From f1f4e83fd9b5ce77d05825586d0426a54b8f3a68 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 499/563] [PATCH] x86-64: White space and comment fixes for smp_call_function_single No functional changes Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/smp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c index e5958220d6b8b..82d38f145b437 100644 --- a/arch/x86_64/kernel/smp.c +++ b/arch/x86_64/kernel/smp.c @@ -295,8 +295,11 @@ void unlock_ipi_call_lock(void) /* * this function sends a 'generic call function' IPI to one other CPU * in the system. + * + * cpu is a standard Linux logical CPU number. */ -static void __smp_call_function_single (int cpu, void (*func) (void *info), void *info, +static void +__smp_call_function_single(int cpu, void (*func) (void *info), void *info, int nonatomic, int wait) { struct call_data_struct data; -- GitLab From 0b07e984fc7a51b1a7c75e1bfdcf59d1ad065353 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 500/563] [PATCH] x86-64: Don't assign CPU numbers in SRAT parsing Do that later when the CPU boots. SRAT just stores the APIC<->Node mapping node. This fixes problems on systems where the order of SRAT entries does not match the MADT. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/setup.c | 21 +++++++++++++-------- arch/x86_64/mm/numa.c | 3 +++ arch/x86_64/mm/srat.c | 17 +++-------------- include/asm-x86_64/numa.h | 2 ++ 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 9aec524be3ebb..976ebcf96f3e9 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -765,6 +765,7 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) int cpu = smp_processor_id(); int node = 0; unsigned bits; + unsigned apicid = phys_proc_id[cpu]; bits = 0; while ((1 << bits) < c->x86_num_cores) @@ -777,15 +778,19 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) #ifdef CONFIG_NUMA /* When an ACPI SRAT table is available use the mappings from SRAT - instead. */ - if (acpi_numa <= 0) { - node = phys_proc_id[cpu]; - if (!node_online(node)) - node = first_node(node_online_map); - cpu_to_node[cpu] = node; - } else { - node = cpu_to_node[cpu]; + instead. */ + node = phys_proc_id[cpu]; + if (acpi_numa > 0) { + if (apicid_to_node[apicid] != NUMA_NO_NODE) + node = apicid_to_node[apicid]; + else + printk(KERN_ERR + "SRAT: Didn't specify node for CPU %d(%d)\n", + cpu, apicid); } + if (!node_online(node)) + node = first_node(node_online_map); + cpu_to_node[cpu] = node; #endif printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n", diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 04f7a33e144c4..5b15186298938 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -29,6 +29,9 @@ int memnode_shift; u8 memnodemap[NODEMAPSIZE]; unsigned char cpu_to_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = NUMA_NO_NODE }; +unsigned char apicid_to_node[256] __cpuinitdata = { + [0 ... NR_CPUS-1] = NUMA_NO_NODE +}; cpumask_t node_to_cpumask[MAX_NUMNODES] __read_mostly; int numa_off __initdata; diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 8e3d097a9dddd..92f6ec79b2322 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -20,9 +20,6 @@ static struct acpi_table_slit *acpi_slit; -/* Internal processor count */ -static unsigned int __initdata num_processors = 0; - static nodemask_t nodes_parsed __initdata; static nodemask_t nodes_found __initdata; static struct node nodes[MAX_NUMNODES] __initdata; @@ -104,18 +101,10 @@ acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa) bad_srat(); return; } - if (num_processors >= NR_CPUS) { - printk(KERN_ERR "SRAT: Processor #%d (lapic %u) INVALID. (Max ID: %d).\n", - num_processors, pa->apic_id, NR_CPUS); - bad_srat(); - return; - } - cpu_to_node[num_processors] = node; + apicid_to_node[pa->apic_id] = node; acpi_numa = 1; - printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> CPU %u -> Node %u\n", - pxm, pa->apic_id, num_processors, node); - - num_processors++; + printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n", + pxm, pa->apic_id, node); } /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ diff --git a/include/asm-x86_64/numa.h b/include/asm-x86_64/numa.h index 5c363a1482e43..3aaf700272133 100644 --- a/include/asm-x86_64/numa.h +++ b/include/asm-x86_64/numa.h @@ -16,6 +16,8 @@ extern void numa_add_cpu(int cpu); extern void numa_init_array(void); extern int numa_off; +extern unsigned char apicid_to_node[256]; + #define NUMA_NO_NODE 0xff #endif -- GitLab From 8675b1a454016c7c50215552ea5c5c4a2413fda0 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 501/563] [PATCH] x86-64: Fix the apic version that gets printed during boot Signed-off-by: Suresh Sidda <suresh.b.siddha@intel.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/mpparse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index 8d8ed6ae1d0c8..312ecc9e5f7f0 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -705,7 +705,7 @@ void __init mp_register_lapic ( processor.mpc_type = MP_PROCESSOR; processor.mpc_apicid = id; - processor.mpc_apicver = 0x10; /* TBD: lapic version */ + processor.mpc_apicver = GET_APIC_VERSION(apic_read(APIC_LVR)); processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0); processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0); processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | -- GitLab From b91691164be174b780f5c1bb145a7ab5d33fce2f Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 502/563] [PATCH] x86-64: Don't cache align PDA on UP builds Suggested by someone I forgot who sorry. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-x86_64/pda.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-x86_64/pda.h b/include/asm-x86_64/pda.h index 36b766cfc4d56..e16d76c9deb0d 100644 --- a/include/asm-x86_64/pda.h +++ b/include/asm-x86_64/pda.h @@ -22,7 +22,7 @@ struct x8664_pda { struct mm_struct *active_mm; int mmu_state; unsigned apic_timer_irqs; -} ____cacheline_aligned; +} ____cacheline_aligned_in_smp; #define IRQSTACK_ORDER 2 -- GitLab From 3f098c2605bdf50176b26f4fa724e9b9c99e5242 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 503/563] [PATCH] x86-64: Support dualcore and 8 socket systems in k8 fallback node parsing In particular on systems where the local APIC space and node space is very different from the Linux CPU number space. Previously the older NUMA setup code directly parsing the K8 northbridge registers had some issues on 8 socket or dual core systems. This patch fixes them. This is mainly done by fixing some confusion between Linux CPU numbers and local APIC ids. We now pass the local APIC IDs to later code, which avoids mismatches. Also add some heuristics to detect cases where the Hypertransport nodeids and the local APIC IDs don't match, but are shifted by a constant offset. This is still all quite hackish, hopefully BIOS writers fill in correct SRATs instead. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/setup.c | 64 ++++++++++++++++++++++++++---------- arch/x86_64/mm/k8topology.c | 13 ++++++-- arch/x86_64/mm/numa.c | 10 +++--- include/asm-x86_64/apicdef.h | 1 + 4 files changed, 63 insertions(+), 25 deletions(-) diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 976ebcf96f3e9..df55a63f88667 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -755,6 +755,24 @@ static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c) } } +#ifdef CONFIG_NUMA +static int nearby_node(int apicid) +{ + int i; + for (i = apicid - 1; i >= 0; i--) { + int node = apicid_to_node[i]; + if (node != NUMA_NO_NODE && node_online(node)) + return node; + } + for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) { + int node = apicid_to_node[i]; + if (node != NUMA_NO_NODE && node_online(node)) + return node; + } + return first_node(node_online_map); /* Shouldn't happen */ +} +#endif + /* * On a AMD dual core setup the lower bits of the APIC id distingush the cores. * Assumes number of cores is a power of two. @@ -763,9 +781,11 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) { #ifdef CONFIG_SMP int cpu = smp_processor_id(); - int node = 0; unsigned bits; +#ifdef CONFIG_NUMA + int node = 0; unsigned apicid = phys_proc_id[cpu]; +#endif bits = 0; while ((1 << bits) < c->x86_num_cores) @@ -777,24 +797,32 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) phys_proc_id[cpu] >>= bits; #ifdef CONFIG_NUMA - /* When an ACPI SRAT table is available use the mappings from SRAT - instead. */ - node = phys_proc_id[cpu]; - if (acpi_numa > 0) { - if (apicid_to_node[apicid] != NUMA_NO_NODE) - node = apicid_to_node[apicid]; - else - printk(KERN_ERR - "SRAT: Didn't specify node for CPU %d(%d)\n", - cpu, apicid); - } - if (!node_online(node)) - node = first_node(node_online_map); - cpu_to_node[cpu] = node; + node = phys_proc_id[cpu]; + if (apicid_to_node[apicid] != NUMA_NO_NODE) + node = apicid_to_node[apicid]; + if (!node_online(node)) { + /* Two possibilities here: + - The CPU is missing memory and no node was created. + In that case try picking one from a nearby CPU + - The APIC IDs differ from the HyperTransport node IDs + which the K8 northbridge parsing fills in. + Assume they are all increased by a constant offset, + but in the same order as the HT nodeids. + If that doesn't result in a usable node fall back to the + path for the previous case. */ + int ht_nodeid = apicid - (phys_proc_id[0] << bits); + if (ht_nodeid >= 0 && + apicid_to_node[ht_nodeid] != NUMA_NO_NODE) + node = apicid_to_node[ht_nodeid]; + /* Pick a nearby node */ + if (!node_online(node)) + node = nearby_node(apicid); + } + cpu_to_node[cpu] = node; + + printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n", + cpu, c->x86_num_cores, node, cpu_core_id[cpu]); #endif - - printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n", - cpu, c->x86_num_cores, node, cpu_core_id[cpu]); #endif } diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c index ec35747aacd76..65417b040c1bf 100644 --- a/arch/x86_64/mm/k8topology.c +++ b/arch/x86_64/mm/k8topology.c @@ -45,10 +45,12 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) unsigned long prevbase; struct node nodes[8]; int nodeid, i, nb; + unsigned char nodeids[8]; int found = 0; u32 reg; unsigned numnodes; nodemask_t nodes_parsed; + unsigned dualcore = 0; nodes_clear(nodes_parsed); @@ -67,11 +69,15 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) prevbase = 0; for (i = 0; i < 8; i++) { unsigned long base,limit; - + u32 nodeid; + + /* Undefined before E stepping, but hopefully 0 */ + dualcore |= ((read_pci_config(0, nb, 3, 0xe8) >> 12) & 3) == 1; base = read_pci_config(0, nb, 1, 0x40 + i*8); limit = read_pci_config(0, nb, 1, 0x44 + i*8); nodeid = limit & 7; + nodeids[i] = nodeid; if ((base & 3) == 0) { if (i < numnodes) printk("Skipping disabled node %d\n", i); @@ -157,8 +163,9 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end) for (i = 0; i < 8; i++) { if (nodes[i].start != nodes[i].end) { - /* assume 1:1 NODE:CPU */ - cpu_to_node[i] = i; + nodeid = nodeids[i]; + apicid_to_node[nodeid << dualcore] = i; + apicid_to_node[(nodeid << dualcore) + dualcore] = i; setup_node_bootmem(i, nodes[i].start, nodes[i].end); } } diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 5b15186298938..80a49d9bd8a77 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -28,11 +28,13 @@ bootmem_data_t plat_node_bdata[MAX_NUMNODES]; int memnode_shift; u8 memnodemap[NODEMAPSIZE]; -unsigned char cpu_to_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = NUMA_NO_NODE }; -unsigned char apicid_to_node[256] __cpuinitdata = { - [0 ... NR_CPUS-1] = NUMA_NO_NODE +unsigned char cpu_to_node[NR_CPUS] __read_mostly = { + [0 ... NR_CPUS-1] = NUMA_NO_NODE }; -cpumask_t node_to_cpumask[MAX_NUMNODES] __read_mostly; +unsigned char apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = { + [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE +}; +cpumask_t node_to_cpumask[MAX_NUMNODES] __read_mostly; int numa_off __initdata; diff --git a/include/asm-x86_64/apicdef.h b/include/asm-x86_64/apicdef.h index 9388062c4f6e5..fb1c99ac669fd 100644 --- a/include/asm-x86_64/apicdef.h +++ b/include/asm-x86_64/apicdef.h @@ -113,6 +113,7 @@ #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) #define MAX_IO_APICS 128 +#define MAX_LOCAL_APIC 256 /* * All x86-64 systems are xAPIC compatible. -- GitLab From df0cc26b1b7f88f46307eea50a7469f0b58132d9 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 504/563] [PATCH] x86-64: Use SRAT data on Intel systems too. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/setup.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index df55a63f88667..869770da29331 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -942,6 +942,25 @@ static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c) return 1; } +static void srat_detect_node(void) +{ +#ifdef CONFIG_NUMA + unsigned apicid, node; + int cpu = smp_processor_id(); + + /* Don't do the funky fallback heuristics the AMD version employs + for now. */ + apicid = phys_proc_id[cpu]; + node = apicid_to_node[apicid]; + if (node == NUMA_NO_NODE) + node = 0; + cpu_to_node[cpu] = node; + + if (acpi_numa > 0) + printk(KERN_INFO "CPU %d -> Node %d\n", cpu, node); +#endif +} + static void __cpuinit init_intel(struct cpuinfo_x86 *c) { /* Cache sizes */ @@ -960,6 +979,8 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) if (c->x86 >= 15) set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability); c->x86_num_cores = intel_num_cpu_cores(c); + + srat_detect_node(); } static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c) -- GitLab From 357e11d4cbbbb959a88a9bdbbf33a10f160b0823 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 505/563] [PATCH] x86-64: Don't assume APIC for boot processor has an APIC ID of zero Originally from Stuart Hayes. When setting up the APIC for the Uniprocessor kernel don't assume the CPU has an APIC ID of zero. This fixes boot with the UP kernel on Dell PowerEdge 6800/6850 4way systems. Cc: Stuart.Hayes@dell.com Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index fc84bea42fd41..12e9d6ca7222e 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -1051,7 +1051,7 @@ int __init APIC_init_uniprocessor (void) connect_bsp_APIC(); - phys_cpu_present_map = physid_mask_of_physid(0); + phys_cpu_present_map = physid_mask_of_physid(boot_cpu_id); apic_write_around(APIC_ID, boot_cpu_id); setup_local_APIC(); -- GitLab From 6142891a0c0209c91aa4a98f725de0d6e2ed4918 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 506/563] [PATCH] x86-64: Avoid unnecessary double bouncing for swiotlb PCI_DMA_BUS_IS_PHYS has to be zero even when the GART IOMMU is disabled and the swiotlb is used. Otherwise the block layer does unnecessary double bouncing. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-x86_64/pci.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h index eeb3088a1c9e3..5a82a6762c218 100644 --- a/include/asm-x86_64/pci.h +++ b/include/asm-x86_64/pci.h @@ -50,10 +50,10 @@ extern int iommu_setup(char *opt); * address space. The networking and block device layers use * this boolean for bounce buffer decisions * - * On AMD64 it mostly equals, but we set it to zero to tell some subsystems - * that an IOMMU is available. + * On x86-64 it mostly equals, but we set it to zero to tell some subsystems + * that an hard or soft IOMMU is available. */ -#define PCI_DMA_BUS_IS_PHYS (no_iommu ? 1 : 0) +#define PCI_DMA_BUS_IS_PHYS 0 /* * x86-64 always supports DAC, but sometimes it is useful to force -- GitLab From 5d3d0f7704ed0bc7eaca0501eeae3e5da1ea6c87 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 507/563] [PATCH] x86-64: Reverse order of bootmem lists This leads to bootmem allocating first from node 0 instead of from the last node. This avoids swiotlb allocating on the last node, which doesn't really work on a machine with >4GB. Note: there is a better patch around from someone else that gets rid of the pgdat list completely. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- mm/bootmem.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mm/bootmem.c b/mm/bootmem.c index c1330cc197835..8ec4e4c2a179f 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -61,9 +61,17 @@ static unsigned long __init init_bootmem_core (pg_data_t *pgdat, { bootmem_data_t *bdata = pgdat->bdata; unsigned long mapsize = ((end - start)+7)/8; - - pgdat->pgdat_next = pgdat_list; - pgdat_list = pgdat; + static struct pglist_data *pgdat_last; + + pgdat->pgdat_next = NULL; + /* Add new nodes last so that bootmem always starts + searching in the first nodes, not the last ones */ + if (pgdat_last) + pgdat_last->pgdat_next = pgdat; + else { + pgdat_list = pgdat; + pgdat_last = pgdat; + } mapsize = ALIGN(mapsize, sizeof(long)); bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); -- GitLab From 63f02fd7ceb2fa4065d8a0c9943e4af2876b6c91 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 508/563] [PATCH] x86-64: Don't allocate aperture when swiotlb is enabled and no AGP found No-one needs it then Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/aperture.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c index c9a6b812e926c..962ad4823b6a5 100644 --- a/arch/x86_64/kernel/aperture.c +++ b/arch/x86_64/kernel/aperture.c @@ -245,6 +245,8 @@ void __init iommu_hole_init(void) if (aper_alloc) { /* Got the aperture from the AGP bridge */ + } else if (swiotlb && !valid_agp) { + /* Do nothing */ } else if ((!no_iommu && end_pfn >= 0xffffffff>>PAGE_SHIFT) || force_iommu || valid_agp || -- GitLab From a54e678b8f476d6f28e6aa4409f6b88ce476af1b Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 509/563] [PATCH] x86-64: Remove redundant swiotlb=force handling It's already handled in the main swiotlb code. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/mm/init.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index aa4a5189ecee2..47cf9163aa89f 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -403,8 +403,6 @@ static inline int page_is_ram (unsigned long pagenr) return 0; } -extern int swiotlb_force; - static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules, kcore_vsyscall; @@ -414,8 +412,6 @@ void __init mem_init(void) int tmp; #ifdef CONFIG_SWIOTLB - if (swiotlb_force) - swiotlb = 1; if (!iommu_aperture && (end_pfn >= 0xffffffff>>PAGE_SHIFT || force_iommu)) swiotlb = 1; -- GitLab From 673242c10d535bfe238d9d8e82ac93432d35b88e Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 510/563] [PATCH] x86-64: Make lockless machine check record passing a bit more robust. One machine is constantly throwing NMI watchdog timeouts in mce_log This was one attempt to fix it. (AK: this doesn't actually fix the bug I'm seeing unfortunately, probably drop. I don't like it that the reader can spin forever now waiting for a writer) Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/mce.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 8aa56736cde38..87ea8fdd43fd9 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -56,15 +56,19 @@ void mce_log(struct mce *mce) smp_wmb(); for (;;) { entry = rcu_dereference(mcelog.next); - /* When the buffer fills up discard new entries. Assume - that the earlier errors are the more interesting. */ - if (entry >= MCE_LOG_LEN) { - set_bit(MCE_OVERFLOW, &mcelog.flags); - return; + for (;;) { + /* When the buffer fills up discard new entries. Assume + that the earlier errors are the more interesting. */ + if (entry >= MCE_LOG_LEN) { + set_bit(MCE_OVERFLOW, &mcelog.flags); + return; + } + /* Old left over entry. Skip. */ + if (mcelog.entry[entry].finished) { + entry++; + continue; + } } - /* Old left over entry. Skip. */ - if (mcelog.entry[entry].finished) - continue; smp_rmb(); next = entry + 1; if (cmpxchg(&mcelog.next, entry, next) == entry) @@ -404,9 +408,15 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff } err = 0; - for (i = 0; i < next; i++) { - if (!mcelog.entry[i].finished) - continue; + for (i = 0; i < next; i++) { + unsigned long start = jiffies; + while (!mcelog.entry[i].finished) { + if (!time_before(jiffies, start + 2)) { + memset(mcelog.entry + i,0, sizeof(struct mce)); + continue; + } + cpu_relax(); + } smp_rmb(); err |= copy_to_user(buf, mcelog.entry + i, sizeof(struct mce)); buf += sizeof(struct mce); -- GitLab From 8c566ef5f3eb5d9daf61d0fa31d82c211f601ba0 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 511/563] [PATCH] x86-64: Add command line option to set machine check tolerance level Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/x86_64/boot-options.txt | 5 +++++ arch/x86_64/kernel/mce.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt index 678e8f192db29..ffe1c062088b9 100644 --- a/Documentation/x86_64/boot-options.txt +++ b/Documentation/x86_64/boot-options.txt @@ -11,6 +11,11 @@ Machine check If your BIOS doesn't do that it's a good idea to enable though to make sure you log even machine check events that result in a reboot. + mce=tolerancelevel (number) + 0: always panic, 1: panic if deadlock possible, + 2: try to avoid panic, 3: never panic or exit (for testing) + default is 1 + Can be also set using sysfs which is preferable. nomce (for compatibility with i386): same as mce=off diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 87ea8fdd43fd9..a39a3edf9ed43 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -17,6 +17,7 @@ #include <linux/fs.h> #include <linux/cpu.h> #include <linux/percpu.h> +#include <linux/ctype.h> #include <asm/processor.h> #include <asm/msr.h> #include <asm/mce.h> @@ -489,6 +490,7 @@ static int __init mcheck_disable(char *str) /* mce=off disables machine check. Note you can reenable it later using sysfs. + mce=TOLERANCELEVEL (number, see above) mce=bootlog Log MCEs from before booting. Disabled by default to work around buggy BIOS that leave bogus MCEs. */ static int __init mcheck_enable(char *str) @@ -499,6 +501,8 @@ static int __init mcheck_enable(char *str) mce_dont_init = 1; else if (!strcmp(str, "bootlog")) mce_bootlog = 1; + else if (isdigit(str[0])) + get_option(&str, &tolerant); else printk("mce= argument %s ignored. Please use /sys", str); return 0; -- GitLab From 1d3fbbf9fe8d5cd5f94256781cc69a4ac289a767 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 512/563] [PATCH] x86-64: Don't trust boot_cpu_id in the mptable. It could be wrong for kexec or other cases. Read it from the CPU instead. Signed-off-by: Murali <muralim@in.ibm.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/apic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 12e9d6ca7222e..a759f4e745570 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -622,8 +622,7 @@ void __init init_apic_mappings(void) * Fetch the APIC ID of the BSP in case we have a * default configuration (or the MP table is broken). */ - if (boot_cpu_id == -1U) - boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID)); + boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID)); #ifdef CONFIG_X86_IO_APIC { -- GitLab From 117090b5e815d0075bff85c2be954d68a11ac4ed Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 513/563] [PATCH] x86-64: Micro optimization to dma_alloc_coherent node lookup Use pcibus_to_node directly Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/pci-gart.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c index 57f35c68aa34d..cf0a0315d586a 100644 --- a/arch/x86_64/kernel/pci-gart.c +++ b/arch/x86_64/kernel/pci-gart.c @@ -191,11 +191,9 @@ static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order) { struct page *page; int node; - if (dev->bus == &pci_bus_type) { - cpumask_t mask; - mask = pcibus_to_cpumask(to_pci_dev(dev)->bus); - node = cpu_to_node(first_cpu(mask)); - } else + if (dev->bus == &pci_bus_type) + node = pcibus_to_node(to_pci_dev(dev)->bus); + else node = numa_node_id(); page = alloc_pages_node(node, gfp, order); return page ? page_address(page) : NULL; -- GitLab From 7c7a3897f678cfafebc8ec0a5e61a814f2f24e42 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 514/563] [PATCH] x86-64: Fix harmless off by one in e820 code Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/e820.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index bb0ae18ec02b9..eb7929eea7b33 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -131,7 +131,7 @@ void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned lon if (ei->type != E820_RAM || ei->addr+ei->size <= start || - ei->addr > end) + ei->addr >= end) continue; addr = round_up(ei->addr, PAGE_SIZE); -- GitLab From 0a43e4bf7489074c667f24b9670ecd88f6eb0a07 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 515/563] [PATCH] x86-64: Use e820_find_hole to compute reserved pages Avoids a very dumb loop Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/mm/init.c | 42 +++++------------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 47cf9163aa89f..5659d979316dd 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -381,35 +381,12 @@ void __init clear_kernel_mapping(unsigned long address, unsigned long size) __flush_tlb_all(); } -static inline int page_is_ram (unsigned long pagenr) -{ - int i; - - for (i = 0; i < e820.nr_map; i++) { - unsigned long addr, end; - - if (e820.map[i].type != E820_RAM) /* not usable memory */ - continue; - /* - * !!!FIXME!!! Some BIOSen report areas as RAM that - * are not. Notably the 640->1Mb area. We need a sanity - * check here. - */ - addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT; - end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT; - if ((pagenr >= addr) && (pagenr < end)) - return 1; - } - return 0; -} - static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules, kcore_vsyscall; void __init mem_init(void) { - int codesize, reservedpages, datasize, initsize; - int tmp; + long codesize, reservedpages, datasize, initsize; #ifdef CONFIG_SWIOTLB if (!iommu_aperture && @@ -432,25 +409,16 @@ void __init mem_init(void) /* this will put all low memory onto the freelists */ #ifdef CONFIG_NUMA - totalram_pages += numa_free_all_bootmem(); - tmp = 0; - /* should count reserved pages here for all nodes */ + totalram_pages = numa_free_all_bootmem(); #else #ifdef CONFIG_FLATMEM max_mapnr = end_pfn; if (!mem_map) BUG(); #endif - - totalram_pages += free_all_bootmem(); - - for (tmp = 0; tmp < end_pfn; tmp++) - /* - * Only count reserved RAM pages - */ - if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp))) - reservedpages++; + totalram_pages = free_all_bootmem(); #endif + reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn); after_bootmem = 1; @@ -467,7 +435,7 @@ void __init mem_init(void) kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START, VSYSCALL_END - VSYSCALL_START); - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", + printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), end_pfn << (PAGE_SHIFT-10), codesize >> 10, -- GitLab From b9aac10dddd927f0b9cfcca19a272ded87015574 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 516/563] [PATCH] x86-64: Remove redundant max_mapnr and replace with end_pfn The FLATMEM people added it, but there doesn't seem a good reason because end_pfn is identical. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/mm/init.c | 5 ----- include/asm-x86_64/page.h | 4 +++- include/asm-x86_64/proto.h | 2 -- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 5659d979316dd..b6a826d6c1822 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -411,11 +411,6 @@ void __init mem_init(void) #ifdef CONFIG_NUMA totalram_pages = numa_free_all_bootmem(); #else - -#ifdef CONFIG_FLATMEM - max_mapnr = end_pfn; - if (!mem_map) BUG(); -#endif totalram_pages = free_all_bootmem(); #endif reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn); diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h index 135ffaa0393b4..e5ab4d231f2ce 100644 --- a/include/asm-x86_64/page.h +++ b/include/asm-x86_64/page.h @@ -32,6 +32,8 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ +extern unsigned long end_pfn; + void clear_page(void *); void copy_page(void *, void *); @@ -111,7 +113,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; #ifdef CONFIG_FLATMEM #define pfn_to_page(pfn) (mem_map + (pfn)) #define page_to_pfn(page) ((unsigned long)((page) - mem_map)) -#define pfn_valid(pfn) ((pfn) < max_mapnr) +#define pfn_valid(pfn) ((pfn) < end_pfn) #endif #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index f7574196424e1..764b5f822ce28 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -93,8 +93,6 @@ extern int unhandled_signal(struct task_struct *tsk, int sig); extern void select_idle_routine(const struct cpuinfo_x86 *c); extern void swiotlb_init(void); -extern unsigned long max_mapnr; -extern unsigned long end_pfn; extern unsigned long table_start, table_end; extern int exception_trace; -- GitLab From 413588c7cb8113c03d0044f1d41b832ad7201c29 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 517/563] [PATCH] x86-64: Remove code to resume machine check state of other CPUs. The resume code uses CPU hotplug now so at resume time we only ever see one CPU. Pointed out by Yu Luming. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/mce.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index a39a3edf9ed43..969365c0771b2 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -515,10 +515,12 @@ __setup("mce", mcheck_enable); * Sysfs support */ -/* On resume clear all MCE state. Don't want to see leftovers from the BIOS. */ +/* On resume clear all MCE state. Don't want to see leftovers from the BIOS. + Only one CPU is active at this time, the others get readded later using + CPU hotplug. */ static int mce_resume(struct sys_device *dev) { - on_each_cpu(mce_init, NULL, 1, 1); + mce_init(NULL); return 0; } -- GitLab From 69e1a33f62eff9b228a8cc2c3e4429dbee8966c9 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 518/563] [PATCH] x86-64: Use ACPI PXM to parse PCI<->node assignments Since this is shared code I had to implement it for i386 too Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/i386/kernel/srat.c | 8 +++++++- arch/i386/pci/acpi.c | 17 ++++++++++++++++- arch/x86_64/kernel/mpparse.c | 2 -- arch/x86_64/mm/srat.c | 7 +++++++ arch/x86_64/pci/k8-bus.c | 10 ++++++++-- include/asm-i386/numa.h | 3 +++ include/asm-i386/topology.h | 2 +- include/asm-x86_64/numa.h | 1 + include/asm-x86_64/topology.h | 3 +-- 9 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 include/asm-i386/numa.h diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c index 7b3b27d644093..516bf5653b026 100644 --- a/arch/i386/kernel/srat.c +++ b/arch/i386/kernel/srat.c @@ -213,12 +213,18 @@ static __init void node_read_chunk(int nid, struct node_memory_chunk_s *memory_c node_end_pfn[nid] = memory_chunk->end_pfn; } +static u8 pxm_to_nid_map[MAX_PXM_DOMAINS];/* _PXM to logical node ID map */ + +int pxm_to_node(int pxm) +{ + return pxm_to_nid_map[pxm]; +} + /* Parse the ACPI Static Resource Affinity Table */ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) { u8 *start, *end, *p; int i, j, nid; - u8 pxm_to_nid_map[MAX_PXM_DOMAINS];/* _PXM to logical node ID map */ u8 nid_to_pxm_map[MAX_NUMNODES];/* logical node ID to _PXM map */ start = (u8 *)(&(sratp->reserved) + 1); /* skip header */ diff --git a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c index 42913f43feb0e..2941674f35eb5 100644 --- a/arch/i386/pci/acpi.c +++ b/arch/i386/pci/acpi.c @@ -3,16 +3,31 @@ #include <linux/init.h> #include <linux/irq.h> #include <asm/hw_irq.h> +#include <asm/numa.h> #include "pci.h" struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) { + struct pci_bus *bus; + if (domain != 0) { printk(KERN_WARNING "PCI: Multiple domains not supported\n"); return NULL; } - return pcibios_scan_root(busnum); + bus = pcibios_scan_root(busnum); +#ifdef CONFIG_ACPI_NUMA + if (bus != NULL) { + int pxm = acpi_get_pxm(device->handle); + if (pxm >= 0) { + bus->sysdata = (void *)(unsigned long)pxm_to_node(pxm); + printk("bus %d -> pxm %d -> node %ld\n", + busnum, pxm, (long)(bus->sysdata)); + } + } +#endif + + return bus; } extern int pci_routeirq; diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index 312ecc9e5f7f0..11642526c5b7e 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -46,8 +46,6 @@ int acpi_found_madt; int apic_version [MAX_APICS]; unsigned char mp_bus_id_to_type [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; -unsigned char pci_bus_to_node [256]; -EXPORT_SYMBOL(pci_bus_to_node); static int mp_current_pci_id = 0; /* I/O APIC entries */ diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 92f6ec79b2322..db6b073a149ff 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -25,6 +25,13 @@ static nodemask_t nodes_found __initdata; static struct node nodes[MAX_NUMNODES] __initdata; static __u8 pxm2node[256] = { [0 ... 255] = 0xff }; +int pxm_to_node(int pxm) +{ + if ((unsigned)pxm >= 256) + return 0; + return pxm2node[pxm]; +} + static __init int setup_node(int pxm) { unsigned node = pxm2node[pxm]; diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c index d80c323669e0c..3acf60ded2a0b 100644 --- a/arch/x86_64/pci/k8-bus.c +++ b/arch/x86_64/pci/k8-bus.c @@ -58,10 +58,16 @@ fill_mp_bus_to_cpumask(void) for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus); j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus); j++) { - int node = NODE_ID(nid); + struct pci_bus *bus; + long node = NODE_ID(nid); + /* Algorithm a bit dumb, but + it shouldn't matter here */ + bus = pci_find_bus(0, j); + if (!bus) + continue; if (!node_online(node)) node = 0; - pci_bus_to_node[j] = node; + bus->sysdata = (void *)node; } } } diff --git a/include/asm-i386/numa.h b/include/asm-i386/numa.h new file mode 100644 index 0000000000000..96fcb157db1d9 --- /dev/null +++ b/include/asm-i386/numa.h @@ -0,0 +1,3 @@ + +int pxm_to_nid(int pxm); + diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h index 2461b731781eb..0ec27c9e8e45b 100644 --- a/include/asm-i386/topology.h +++ b/include/asm-i386/topology.h @@ -60,7 +60,7 @@ static inline int node_to_first_cpu(int node) return first_cpu(mask); } -#define pcibus_to_node(bus) mp_bus_id_to_node[(bus)->number] +#define pcibus_to_node(bus) ((long) (bus)->sysdata) #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus)) /* sched_domains SD_NODE_INIT for NUMAQ machines */ diff --git a/include/asm-x86_64/numa.h b/include/asm-x86_64/numa.h index 3aaf700272133..bcf55c3f7f7f3 100644 --- a/include/asm-x86_64/numa.h +++ b/include/asm-x86_64/numa.h @@ -9,6 +9,7 @@ struct node { }; extern int compute_hash_shift(struct node *nodes, int numnodes); +extern int pxm_to_node(int nid); #define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT)) diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h index c1bc3fad482ed..1c603cd7e4d09 100644 --- a/include/asm-x86_64/topology.h +++ b/include/asm-x86_64/topology.h @@ -13,7 +13,6 @@ extern cpumask_t cpu_online_map; extern unsigned char cpu_to_node[]; -extern unsigned char pci_bus_to_node[]; extern cpumask_t node_to_cpumask[]; #ifdef CONFIG_ACPI_NUMA @@ -26,7 +25,7 @@ extern int __node_distance(int, int); #define parent_node(node) (node) #define node_to_first_cpu(node) (__ffs(node_to_cpumask[node])) #define node_to_cpumask(node) (node_to_cpumask[node]) -#define pcibus_to_node(bus) pci_bus_to_node[(bus)->number] +#define pcibus_to_node(bus) ((long)(bus->sysdata)) #define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus)); /* sched_domains SD_NODE_INIT for x86_64 machines */ -- GitLab From 9acf23c42b13d682abbd5db1d293c7a77ae54b61 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 519/563] [PATCH] x86-64: Include build number in oops output Include build number in oops output Helps me to match oopses to correct kernel. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/process.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 8661f82ac70b4..b19cee6a12e6c 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -271,8 +271,11 @@ void __show_regs(struct pt_regs * regs) printk("\n"); print_modules(); - printk("Pid: %d, comm: %.20s %s %s\n", - current->pid, current->comm, print_tainted(), system_utsname.release); + printk("Pid: %d, comm: %.20s %s %s %.*s\n", + current->pid, current->comm, print_tainted(), + system_utsname.release, + (int)strcspn(system_utsname.version, " "), + system_utsname.version); printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip); printk_address(regs->rip); printk("\nRSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags); -- GitLab From 83b942bd3437d84d6ddf582477120b6b86369052 Mon Sep 17 00:00:00 2001 From: "Tsuneo.Yoshioka@f-secure.com" <Tsuneo.Yoshioka@f-secure.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 520/563] [PATCH] x86-64: Fix 32bit sendfile If we use 64bit kernel on ia64/x86_64/s390 architecture, and we run 32bit binary on 32bit compatibility mode, sendfile system call seems be not set offset argument. This is because sendfile's return value is not zero but the code regards the result by return value is zero or not. This problem will be affect to ia64/x86_64/s390 and not affect to other architecture does not affect other architecture (mips/parisc/ppc64/sparc64). Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/ia64/ia32/sys_ia32.c | 2 +- arch/s390/kernel/compat_linux.c | 2 +- arch/x86_64/ia32/sys_ia32.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index e29a8a55486a5..3fa67ecebc838 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -2327,7 +2327,7 @@ sys32_sendfile (int out_fd, int in_fd, int __user *offset, unsigned int count) ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *) &of : NULL, count); set_fs(old_fs); - if (!ret && offset && put_user(of, offset)) + if (offset && put_user(of, offset)) return -EFAULT; return ret; diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 18610cea03a21..ed877d0f27e6e 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -678,7 +678,7 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, size ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); set_fs(old_fs); - if (!ret && offset && put_user(of, offset)) + if (offset && put_user(of, offset)) return -EFAULT; return ret; diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index 04d80406ce4fe..5389df610e782 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -751,7 +751,7 @@ sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count) ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); set_fs(old_fs); - if (!ret && offset && put_user(of, offset)) + if (offset && put_user(of, offset)) return -EFAULT; return ret; -- GitLab From e5bc8b6baf86538f3d0407cf0880f86aec828a13 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 521/563] [PATCH] x86-64: Make remote TLB flush more scalable Instead of using a global spinlock to protect the state of the remote TLB flush use a lock and state for each sending CPU. To tell the receiver where to look for the state use 8 different call vectors. Each CPU uses a specific vector to trigger flushes on other CPUs. Depending on the received vector the target CPUs look into the right per cpu variable for the flush data. When the system has more than 8 CPUs they are hashed to the 8 available vectors. The limited global vector space forces us to this right now. In future when interrupts are split into per CPU domains this could be fixed, at the cost of needing more IPIs in flat mode. Also some minor cleanup in the smp flush code and remove some outdated debug code. Requires patch to move cpu_possible_map setup earlier. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/entry.S | 15 ++++- arch/x86_64/kernel/i8259.c | 20 +++++- arch/x86_64/kernel/smp.c | 123 +++++++++++++++++++++++------------- include/asm-x86_64/hw_irq.h | 17 ++--- 4 files changed, 117 insertions(+), 58 deletions(-) diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index 3620508c8bd9b..873c39d8f8184 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -536,8 +536,19 @@ ENTRY(thermal_interrupt) ENTRY(reschedule_interrupt) apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt -ENTRY(invalidate_interrupt) - apicinterrupt INVALIDATE_TLB_VECTOR,smp_invalidate_interrupt + .macro INVALIDATE_ENTRY num +ENTRY(invalidate_interrupt\num) + apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt + .endm + + INVALIDATE_ENTRY 0 + INVALIDATE_ENTRY 1 + INVALIDATE_ENTRY 2 + INVALIDATE_ENTRY 3 + INVALIDATE_ENTRY 4 + INVALIDATE_ENTRY 5 + INVALIDATE_ENTRY 6 + INVALIDATE_ENTRY 7 ENTRY(call_function_interrupt) apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index a891690951299..909fc63c03b61 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -486,7 +486,14 @@ void spurious_interrupt(void); void error_interrupt(void); void reschedule_interrupt(void); void call_function_interrupt(void); -void invalidate_interrupt(void); +void invalidate_interrupt0(void); +void invalidate_interrupt1(void); +void invalidate_interrupt2(void); +void invalidate_interrupt3(void); +void invalidate_interrupt4(void); +void invalidate_interrupt5(void); +void invalidate_interrupt6(void); +void invalidate_interrupt7(void); void thermal_interrupt(void); void i8254_timer_resume(void); @@ -562,8 +569,15 @@ void __init init_IRQ(void) */ set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); - /* IPI for invalidation */ - set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); + /* IPIs for invalidation */ + set_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6); + set_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7); /* IPI for generic function call */ set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c index 82d38f145b437..801db885955ca 100644 --- a/arch/x86_64/kernel/smp.c +++ b/arch/x86_64/kernel/smp.c @@ -29,6 +29,8 @@ #include <asm/proto.h> #include <asm/apicdef.h> +#define __cpuinit __init + /* * Smarter SMP flushing macros. * c/o Linus Torvalds. @@ -37,19 +39,41 @@ * writing to user space from interrupts. (Its not allowed anyway). * * Optimizations Manfred Spraul <manfred@colorfullife.com> + * + * More scalable flush, from Andi Kleen + * + * To avoid global state use 8 different call vectors. + * Each CPU uses a specific vector to trigger flushes on other + * CPUs. Depending on the received vector the target CPUs look into + * the right per cpu variable for the flush data. + * + * With more than 8 CPUs they are hashed to the 8 available + * vectors. The limited global vector space forces us to this right now. + * In future when interrupts are split into per CPU domains this could be + * fixed, at the cost of triggering multiple IPIs in some cases. */ -static cpumask_t flush_cpumask; -static struct mm_struct * flush_mm; -static unsigned long flush_va; -static DEFINE_SPINLOCK(tlbstate_lock); +union smp_flush_state { + struct { + cpumask_t flush_cpumask; + struct mm_struct *flush_mm; + unsigned long flush_va; #define FLUSH_ALL -1ULL + spinlock_t tlbstate_lock; + }; + char pad[SMP_CACHE_BYTES]; +} ____cacheline_aligned; + +/* State is put into the per CPU data section, but padded + to a full cache line because other CPUs can access it and we don't + want false sharing in the per cpu data segment. */ +static DEFINE_PER_CPU(union smp_flush_state, flush_state); /* * We cannot call mmdrop() because we are in interrupt context, * instead update mm->cpu_vm_mask. */ -static inline void leave_mm (unsigned long cpu) +static inline void leave_mm(int cpu) { if (read_pda(mmu_state) == TLBSTATE_OK) BUG(); @@ -101,15 +125,25 @@ static inline void leave_mm (unsigned long cpu) * * 1) Flush the tlb entries if the cpu uses the mm that's being flushed. * 2) Leave the mm if we are in the lazy tlb mode. + * + * Interrupts are disabled. */ -asmlinkage void smp_invalidate_interrupt (void) +asmlinkage void smp_invalidate_interrupt(struct pt_regs *regs) { - unsigned long cpu; + int cpu; + int sender; + union smp_flush_state *f; - cpu = get_cpu(); + cpu = smp_processor_id(); + /* + * orig_rax contains the interrupt vector - 256. + * Use that to determine where the sender put the data. + */ + sender = regs->orig_rax + 256 - INVALIDATE_TLB_VECTOR_START; + f = &per_cpu(flush_state, sender); - if (!cpu_isset(cpu, flush_cpumask)) + if (!cpu_isset(cpu, f->flush_cpumask)) goto out; /* * This was a BUG() but until someone can quote me the @@ -120,64 +154,63 @@ asmlinkage void smp_invalidate_interrupt (void) * BUG(); */ - if (flush_mm == read_pda(active_mm)) { + if (f->flush_mm == read_pda(active_mm)) { if (read_pda(mmu_state) == TLBSTATE_OK) { - if (flush_va == FLUSH_ALL) + if (f->flush_va == FLUSH_ALL) local_flush_tlb(); else - __flush_tlb_one(flush_va); + __flush_tlb_one(f->flush_va); } else leave_mm(cpu); } out: ack_APIC_irq(); - cpu_clear(cpu, flush_cpumask); - put_cpu_no_resched(); + cpu_clear(cpu, f->flush_cpumask); } static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, unsigned long va) { - cpumask_t tmp; - /* - * A couple of (to be removed) sanity checks: - * - * - we do not send IPIs to not-yet booted CPUs. - * - current CPU must not be in mask - * - mask must exist :) - */ - BUG_ON(cpus_empty(cpumask)); - cpus_and(tmp, cpumask, cpu_online_map); - BUG_ON(!cpus_equal(tmp, cpumask)); - BUG_ON(cpu_isset(smp_processor_id(), cpumask)); - if (!mm) - BUG(); + int sender; + union smp_flush_state *f; - /* - * I'm not happy about this global shared spinlock in the - * MM hot path, but we'll see how contended it is. - * Temporarily this turns IRQs off, so that lockups are - * detected by the NMI watchdog. - */ - spin_lock(&tlbstate_lock); - - flush_mm = mm; - flush_va = va; - cpus_or(flush_cpumask, cpumask, flush_cpumask); + /* Caller has disabled preemption */ + sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS; + f = &per_cpu(flush_state, sender); + + /* Could avoid this lock when + num_online_cpus() <= NUM_INVALIDATE_TLB_VECTORS, but it is + probably not worth checking this for a cache-hot lock. */ + spin_lock(&f->tlbstate_lock); + + f->flush_mm = mm; + f->flush_va = va; + cpus_or(f->flush_cpumask, cpumask, f->flush_cpumask); /* * We have to send the IPI only to * CPUs affected. */ - send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR); + send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR_START + sender); - while (!cpus_empty(flush_cpumask)) - mb(); /* nothing. lockup detection does not belong here */; + while (!cpus_empty(f->flush_cpumask)) + cpu_relax(); - flush_mm = NULL; - flush_va = 0; - spin_unlock(&tlbstate_lock); + f->flush_mm = NULL; + f->flush_va = 0; + spin_unlock(&f->tlbstate_lock); } + +int __cpuinit init_smp_flush(void) +{ + int i; + for_each_cpu_mask(i, cpu_possible_map) { + spin_lock_init(&per_cpu(flush_state.tlbstate_lock, i)); + } + return 0; +} + +core_initcall(init_smp_flush); void flush_tlb_current_task(void) { diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index 2b5cb2865d21d..d9212eb4e8946 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -50,14 +50,15 @@ struct hw_interrupt_type; */ #define SPURIOUS_APIC_VECTOR 0xff #define ERROR_APIC_VECTOR 0xfe -#define INVALIDATE_TLB_VECTOR 0xfd -#define RESCHEDULE_VECTOR 0xfc -#define TASK_MIGRATION_VECTOR 0xfb -#define CALL_FUNCTION_VECTOR 0xfa -#define KDB_VECTOR 0xf9 - -#define THERMAL_APIC_VECTOR 0xf0 - +#define RESCHEDULE_VECTOR 0xfd +#define CALL_FUNCTION_VECTOR 0xfc +#define KDB_VECTOR 0xfb /* reserved for KDB */ +#define THERMAL_APIC_VECTOR 0xfa +/* 0xf9 free */ +#define INVALIDATE_TLB_VECTOR_END 0xf8 +#define INVALIDATE_TLB_VECTOR_START 0xf0 /* f0-f8 used for TLB flush */ + +#define NUM_INVALIDATE_TLB_VECTORS 8 /* * Local APIC timer IRQ vector is on a different priority level, -- GitLab From 459192c92cde49d1a2f721c90adf45d774c2dcf5 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 522/563] [PATCH] x86-64: Add simnow console This adds console and earlyprintk support for a host file on AMD's SimNow simulator. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/early_printk.c | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c index 9631c747c5e37..9cd968dd0f5a4 100644 --- a/arch/x86_64/kernel/early_printk.c +++ b/arch/x86_64/kernel/early_printk.c @@ -5,6 +5,7 @@ #include <linux/tty.h> #include <asm/io.h> #include <asm/processor.h> +#include <asm/fcntl.h> /* Simple VGA output */ @@ -158,6 +159,47 @@ static struct console early_serial_console = { .index = -1, }; +/* Console interface to a host file on AMD's SimNow! */ + +static int simnow_fd; + +enum { + MAGIC1 = 0xBACCD00A, + MAGIC2 = 0xCA110000, + XOPEN = 5, + XWRITE = 4, +}; + +static noinline long simnow(long cmd, long a, long b, long c) +{ + long ret; + asm volatile("cpuid" : + "=a" (ret) : + "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2)); + return ret; +} + +void __init simnow_init(char *str) +{ + char *fn = "klog"; + if (*str == '=') + fn = ++str; + /* error ignored */ + simnow_fd = simnow(XOPEN, (unsigned long)fn, O_WRONLY|O_APPEND|O_CREAT, 0644); +} + +static void simnow_write(struct console *con, const char *s, unsigned n) +{ + simnow(XWRITE, simnow_fd, (unsigned long)s, n); +} + +static struct console simnow_console = { + .name = "simnow", + .write = simnow_write, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + /* Direct interface for emergencies */ struct console *early_console = &early_vga_console; static int early_console_initialized = 0; @@ -205,6 +247,10 @@ int __init setup_early_printk(char *opt) max_xpos = SCREEN_INFO.orig_video_cols; max_ypos = SCREEN_INFO.orig_video_lines; early_console = &early_vga_console; + } else if (!strncmp(buf, "simnow", 6)) { + simnow_init(buf + 6); + early_console = &simnow_console; + keep_early = 1; } early_console_initialized = 1; register_console(early_console); -- GitLab From 3f74478b5fd7263e9311cdb320923d599c73a792 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 523/563] [PATCH] x86-64: Some cleanup and optimization to the processor data area. - Remove unused irqrsp field - Remove pda->me - Optimize set_softirq_pending slightly Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/asm-offsets.c | 1 - arch/x86_64/kernel/setup64.c | 1 - include/asm-x86_64/hardirq.h | 9 +++++---- include/asm-x86_64/pda.h | 12 ++++++------ include/linux/interrupt.h | 7 ++++++- kernel/softirq.c | 2 +- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c index 35b4c3fcbb37f..aaa6d38335179 100644 --- a/arch/x86_64/kernel/asm-offsets.c +++ b/arch/x86_64/kernel/asm-offsets.c @@ -39,7 +39,6 @@ int main(void) ENTRY(kernelstack); ENTRY(oldrsp); ENTRY(pcurrent); - ENTRY(irqrsp); ENTRY(irqcount); ENTRY(cpunumber); ENTRY(irqstackptr); diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index e3ffcacc8c90b..e8b54dccb3eea 100644 --- a/arch/x86_64/kernel/setup64.c +++ b/arch/x86_64/kernel/setup64.c @@ -119,7 +119,6 @@ void pda_init(int cpu) asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0)); wrmsrl(MSR_GS_BASE, cpu_pda + cpu); - pda->me = pda; pda->cpunumber = cpu; pda->irqcount = -1; pda->kernelstack = diff --git a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h index 27c381fa1c9d0..8661b476fb404 100644 --- a/include/asm-x86_64/hardirq.h +++ b/include/asm-x86_64/hardirq.h @@ -9,11 +9,12 @@ #define __ARCH_IRQ_STAT 1 -/* Generate a lvalue for a pda member. Should fix softirq.c instead to use - special access macros. This would generate better code. */ -#define __IRQ_STAT(cpu,member) (read_pda(me)->member) +#define local_softirq_pending() read_pda(__softirq_pending) -#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ +#define __ARCH_SET_SOFTIRQ_PENDING 1 + +#define set_softirq_pending(x) write_pda(__softirq_pending, (x)) +#define or_softirq_pending(x) or_pda(__softirq_pending, (x)) /* * 'what should we do if we get a hw irq event on an illegal vector'. diff --git a/include/asm-x86_64/pda.h b/include/asm-x86_64/pda.h index e16d76c9deb0d..bbf89aa8a1afe 100644 --- a/include/asm-x86_64/pda.h +++ b/include/asm-x86_64/pda.h @@ -10,10 +10,8 @@ struct x8664_pda { struct task_struct *pcurrent; /* Current process */ unsigned long data_offset; /* Per cpu data offset from linker address */ - struct x8664_pda *me; /* Pointer to itself */ unsigned long kernelstack; /* top of kernel stack for current */ unsigned long oldrsp; /* user rsp for system call */ - unsigned long irqrsp; /* Old rsp for interrupts. */ int irqcount; /* Irq nesting counter. Starts with -1 */ int cpunumber; /* Logical CPU number */ char *irqstackptr; /* top of irqstack */ @@ -42,13 +40,14 @@ extern void __bad_pda_field(void); #define pda_offset(field) offsetof(struct x8664_pda, field) #define pda_to_op(op,field,val) do { \ + typedef typeof_field(struct x8664_pda, field) T__; \ switch (sizeof_field(struct x8664_pda, field)) { \ case 2: \ -asm volatile(op "w %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \ +asm volatile(op "w %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \ case 4: \ -asm volatile(op "l %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \ +asm volatile(op "l %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \ case 8: \ -asm volatile(op "q %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); break; \ +asm volatile(op "q %0,%%gs:%P1"::"ri" ((T__)val),"i"(pda_offset(field)):"memory"); break; \ default: __bad_pda_field(); \ } \ } while (0) @@ -58,7 +57,7 @@ asm volatile(op "q %0,%%gs:%P1"::"r" (val),"i"(pda_offset(field)):"memory"); bre * Unfortunately removing them causes all hell to break lose currently. */ #define pda_from_op(op,field) ({ \ - typedef typeof_field(struct x8664_pda, field) T__; T__ ret__; \ + typeof_field(struct x8664_pda, field) ret__; \ switch (sizeof_field(struct x8664_pda, field)) { \ case 2: \ asm volatile(op "w %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); break;\ @@ -75,6 +74,7 @@ asm volatile(op "q %%gs:%P1,%0":"=r" (ret__):"i"(pda_offset(field)):"memory"); b #define write_pda(field,val) pda_to_op("mov",field,val) #define add_pda(field,val) pda_to_op("add",field,val) #define sub_pda(field,val) pda_to_op("sub",field,val) +#define or_pda(field,val) pda_to_op("or",field,val) #endif diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index d99e7aeb7d338..0a90205184b0b 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -57,6 +57,11 @@ extern void disable_irq(unsigned int irq); extern void enable_irq(unsigned int irq); #endif +#ifndef __ARCH_SET_SOFTIRQ_PENDING +#define set_softirq_pending(x) (local_softirq_pending() = (x)) +#define or_softirq_pending(x) (local_softirq_pending() |= (x)) +#endif + /* * Temporary defines for UP kernels, until all code gets fixed. */ @@ -123,7 +128,7 @@ struct softirq_action asmlinkage void do_softirq(void); extern void open_softirq(int nr, void (*action)(struct softirq_action*), void *data); extern void softirq_init(void); -#define __raise_softirq_irqoff(nr) do { local_softirq_pending() |= 1UL << (nr); } while (0) +#define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0) extern void FASTCALL(raise_softirq_irqoff(unsigned int nr)); extern void FASTCALL(raise_softirq(unsigned int nr)); diff --git a/kernel/softirq.c b/kernel/softirq.c index b4ab6af1dea85..f766b2fc48be8 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -84,7 +84,7 @@ asmlinkage void __do_softirq(void) cpu = smp_processor_id(); restart: /* Reset the pending bitmask before enabling irqs */ - local_softirq_pending() = 0; + set_softirq_pending(0); local_irq_enable(); -- GitLab From 165aeb82848c81ee1774f8defc74df4341e9184b Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 524/563] [PATCH] x86-64: Don't include config.h in asm/timex.h asm-x86-64/timex.h does not reference CONFIG constants. Do not need to include config.h. Signed-off-by: Grant Grundler <iod00d@hp.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-x86_64/timex.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/asm-x86_64/timex.h b/include/asm-x86_64/timex.h index 24ecf6a637cb4..f971f45d6d78b 100644 --- a/include/asm-x86_64/timex.h +++ b/include/asm-x86_64/timex.h @@ -6,7 +6,6 @@ #ifndef _ASMx8664_TIMEX_H #define _ASMx8664_TIMEX_H -#include <linux/config.h> #include <asm/8253pit.h> #include <asm/msr.h> #include <asm/vsyscall.h> -- GitLab From 2b4a08150e0ce2f6eb5d0987fdfe3524ec799313 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 525/563] [PATCH] x86-64: Increase TLB flush array size The generic TLB flush functions kept upto 506 pages per CPU to avoid too frequent IPIs. This value was done for the L1 cache of older x86 CPUs, but with modern CPUs it does not make much sense anymore. TLB flushing is slow enough that using the L2 cache is fine. This patch increases the flush array on x86-64 to cache 5350 pages. That is roughly 20MB with 4K pages. It speeds up large munmaps in multithreaded processes on SMP considerably. The cost is roughly 42k of memory per CPU, which is reasonable. I only increased it on x86-64 for now, but it would probably make sense to increase it everywhere. Embedded architectures with SMP may keep it smaller to save some memory per CPU. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-generic/tlb.h | 6 +++++- include/asm-x86_64/tlbflush.h | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index faff403e10615..7d0298347ee7d 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h @@ -23,7 +23,11 @@ * and page free order so much.. */ #ifdef CONFIG_SMP - #define FREE_PTE_NR 506 + #ifdef ARCH_FREE_PTR_NR + #define FREE_PTR_NR ARCH_FREE_PTR_NR + #else + #define FREE_PTE_NR 506 + #endif #define tlb_fast_mode(tlb) ((tlb)->nr == ~0U) #else #define FREE_PTE_NR 1 diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h index 505b0cf906ded..4a9c20ea9b105 100644 --- a/include/asm-x86_64/tlbflush.h +++ b/include/asm-x86_64/tlbflush.h @@ -109,6 +109,10 @@ static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long st #define TLBSTATE_OK 1 #define TLBSTATE_LAZY 2 +/* Roughly an IPI every 20MB with 4k pages for freeing page table + ranges. Cost is about 42k of memory for each CPU. */ +#define ARCH_FREE_PTE_NR 5350 + #endif #define flush_tlb_kernel_range(start, end) flush_tlb_all() -- GitLab From e99b861a3e9ec93a48b985519e09b2515c201e8d Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 526/563] [PATCH] x86-64: Only allocate per cpu data for possible CPUs, not compiled in CPUs. Saves some memory except for hotplug situations. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/setup64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index e8b54dccb3eea..bd33be24a3867 100644 --- a/arch/x86_64/kernel/setup64.c +++ b/arch/x86_64/kernel/setup64.c @@ -94,7 +94,7 @@ void __init setup_per_cpu_areas(void) size = PERCPU_ENOUGH_ROOM; #endif - for (i = 0; i < NR_CPUS; i++) { + for_each_cpu_mask (i, cpu_possible_map) { char *ptr; if (!NODE_DATA(cpu_to_node(i))) { -- GitLab From b8f68e9ffaf5e7c9c463ecd2598cc33f8e6df75e Mon Sep 17 00:00:00 2001 From: Hugh Dickins <hugh@veritas.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 527/563] [PATCH] x86-64: Fix idle=poll x86_64 idle=poll might be a little less responsive than it should: unlike mwait_idle, and unlike i386, its poll_idle left TIF_POLLING_NRFLAG set. Signed-off-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index b19cee6a12e6c..e9f35c60f8c6f 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -123,6 +123,7 @@ static void poll_idle (void) : : "i" (_TIF_NEED_RESCHED), "m" (current_thread_info()->flags)); + clear_thread_flag(TIF_POLLING_NRFLAG); } else { set_need_resched(); } -- GitLab From 48496e349554f3704fd1cdf16f389e0615956909 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 528/563] [PATCH] x86-64: Fix (harmless) typo in head.S early level2 page table The global bit was not set in the first 2MB page, instead it had a bit in the free AVL section which is useless. Fixed thus. Noticed by Eric Biederman Cc: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/head.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S index 98ff5eb32b9af..4592bf21fcafa 100644 --- a/arch/x86_64/kernel/head.S +++ b/arch/x86_64/kernel/head.S @@ -270,7 +270,7 @@ ENTRY(level3_kernel_pgt) .org 0x4000 ENTRY(level2_ident_pgt) /* 40MB for bootup. */ - .quad 0x0000000000000283 + .quad 0x0000000000000183 .quad 0x0000000000200183 .quad 0x0000000000400183 .quad 0x0000000000600183 -- GitLab From fe5d5f073eb133b65a8814b48af1722a1ca5aa25 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 529/563] [PATCH] x86-64: Print version at end of kernel build (from i386) Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/boot/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile index f4399c701b779..18c6e915d69b8 100644 --- a/arch/x86_64/boot/Makefile +++ b/arch/x86_64/boot/Makefile @@ -46,7 +46,7 @@ cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \ $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \ $(obj)/vmlinux.bin $(obj)/tools/build FORCE $(call if_changed,image) - @echo 'Kernel: $@ is ready' + @echo 'Kernel: $@ is ready' ' (#'`cat .version`')' $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE $(call if_changed,objcopy) -- GitLab From 083044e63b4d10ebf9afb231bc0d34aec72169b4 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 530/563] [PATCH] x86-64: Remove disable_tsc code in context switch It only offers extremly dubious security advantages and is not worth the overhead in this critical path. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/process.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index e9f35c60f8c6f..687ed357e685e 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -486,33 +486,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, return err; } -/* - * This function selects if the context switch from prev to next - * has to tweak the TSC disable bit in the cr4. - */ -static inline void disable_tsc(struct task_struct *prev_p, - struct task_struct *next_p) -{ - struct thread_info *prev, *next; - - /* - * gcc should eliminate the ->thread_info dereference if - * has_secure_computing returns 0 at compile time (SECCOMP=n). - */ - prev = prev_p->thread_info; - next = next_p->thread_info; - - if (has_secure_computing(prev) || has_secure_computing(next)) { - /* slow path here */ - if (has_secure_computing(prev) && - !has_secure_computing(next)) { - write_cr4(read_cr4() & ~X86_CR4_TSD); - } else if (!has_secure_computing(prev) && - has_secure_computing(next)) - write_cr4(read_cr4() | X86_CR4_TSD); - } -} - /* * This special macro can be used to load a debugging register */ @@ -631,8 +604,6 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct * } } - disable_tsc(prev_p, next_p); - return prev_p; } -- GitLab From e92343cc8e9ca4bc0db4b007dd37d33a207ef637 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 531/563] [PATCH] x86-64: Fix show_mem a little bit - Add KERN_INFO to printks (from i386) - Use longs instead of ints to accumulate pages. - Fix broken indenting. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/mm/init.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index b6a826d6c1822..e60a1a848de8f 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -57,31 +57,31 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); void show_mem(void) { - int i, total = 0, reserved = 0; - int shared = 0, cached = 0; + long i, total = 0, reserved = 0; + long shared = 0, cached = 0; pg_data_t *pgdat; struct page *page; - printk("Mem-info:\n"); + printk(KERN_INFO "Mem-info:\n"); show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); for_each_pgdat(pgdat) { for (i = 0; i < pgdat->node_spanned_pages; ++i) { page = pfn_to_page(pgdat->node_start_pfn + i); total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page) - 1; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page) - 1; } } - printk("%d pages of RAM\n", total); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); - printk("%d pages swap cached\n",cached); + printk(KERN_INFO "%lu pages of RAM\n", total); + printk(KERN_INFO "%lu reserved pages\n",reserved); + printk(KERN_INFO "%lu pages shared\n",shared); + printk(KERN_INFO "%lu pages swap cached\n",cached); } /* References to section boundaries */ -- GitLab From 6e44f12ba64a58f25f8e6f35aa4c175f613001be Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 532/563] [PATCH] i386: add memory clobbers to syscall macros As noted by matz@suse.de The problem is, that on i386 the syscallN macro is defined like so: long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \ If one of the arguments (in the _llseek syscall it's the arg4) is a pointer which the syscall is expected to write to (to the memory pointed to by this ptr), then this side-effect is not captured in the asm. If anyone uses this macro to define it's own version of the syscall (sometimes necessary when not using glibc) and it's inlined, then GCC doesn't know that this asm write to "*dest", when called like so for instance: out = 1; llseek (fd, bla, blubb, &out, trara) use (out); Here nobody tells GCC that "out" actually is written to (just a pointer to it is passed to the asm). Hence GCC might (and in the above bug did) copy-propagate "1" into the second use of "out". The easiest solution would be to add a "memory" clobber to the definition of this syscall macro. As this is a syscall, it shouldn't inhibit too many optimizations. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-i386/unistd.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index a7cb377745bf0..fbaf90a3968c1 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -332,7 +332,7 @@ type name(type1 arg1) \ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1))); \ + : "0" (__NR_##name),"b" ((long)(arg1)) : "memory"); \ __syscall_return(type,__res); \ } @@ -342,7 +342,7 @@ type name(type1 arg1,type2 arg2) \ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \ + : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)) : "memory"); \ __syscall_return(type,__res); \ } @@ -353,7 +353,7 @@ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3))); \ + "d" ((long)(arg3)) : "memory"); \ __syscall_return(type,__res); \ } @@ -364,7 +364,7 @@ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4))); \ + "d" ((long)(arg3)),"S" ((long)(arg4)) : "memory"); \ __syscall_return(type,__res); \ } @@ -376,7 +376,7 @@ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \ + "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)) : "memory"); \ __syscall_return(type,__res); \ } @@ -389,7 +389,7 @@ __asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; p : "=a" (__res) \ : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \ - "0" ((long)(arg6))); \ + "0" ((long)(arg6)) : "memory"); \ __syscall_return(type,__res); \ } -- GitLab From fb048927ad93420b6dd2eddcdde71ea7b6ff95e4 Mon Sep 17 00:00:00 2001 From: Jim Paradis <jparadis@redhat.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 533/563] [PATCH] x86-64: Fix off by one in pfn_valid When I gave proposed the fix to pfn_valid() for RHEL4, Stephen Tweedie's sharp eyes caught this: Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-x86_64/mmzone.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h index 768413751b342..2ef43dac6c283 100644 --- a/include/asm-x86_64/mmzone.h +++ b/include/asm-x86_64/mmzone.h @@ -54,7 +54,7 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr) #define pfn_valid(pfn) ((pfn) >= num_physpages ? 0 : \ ({ u8 nid__ = pfn_to_nid(pfn); \ - nid__ != 0xff && (pfn) >= node_start_pfn(nid__) && (pfn) <= node_end_pfn(nid__); })) + nid__ != 0xff && (pfn) >= node_start_pfn(nid__) && (pfn) < node_end_pfn(nid__); })) #endif #define local_mapnr(kvaddr) \ -- GitLab From f297e4e5e4245a5c3fb36e7f754cde96cdb4bc43 Mon Sep 17 00:00:00 2001 From: Nakul Saraiya <saraiya@fabric7.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 534/563] [PATCH] Increase nodemap hash. Needed for some newer Opteron systems with E stepping and memory relocation enabled. The node addresses are different in lower bits now so the nodemap hash function needs to be enlarged. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-x86_64/mmzone.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h index 2ef43dac6c283..b40c661f111e3 100644 --- a/include/asm-x86_64/mmzone.h +++ b/include/asm-x86_64/mmzone.h @@ -12,7 +12,7 @@ #include <asm/smp.h> -#define NODEMAPSIZE 0xff +#define NODEMAPSIZE 0xfff /* Simple perfect hash to map physical addresses to node numbers */ extern int memnode_shift; -- GitLab From 24dead8ac9c8fa78b9bfb45b06080a7018fd2ed3 Mon Sep 17 00:00:00 2001 From: Alexander Nyberg <alexn@telia.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 535/563] [PATCH] Remove unnecessary BUG_ON in irq.c Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/irq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index 849a20aec7ca0..d6a04a8320a38 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -99,7 +99,6 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) unsigned irq = regs->orig_rax & 0xff; irq_enter(); - BUG_ON(irq > 256); __do_IRQ(irq, regs); irq_exit(); -- GitLab From 016102dea838e8526a4bc57821309f0cd9db81b7 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 536/563] [PATCH] x86-64: Fix typo CONFIG_CPU_HOTPLUG -> CONFIG_HOTPLUG_CPU in genapic.c Noted by Ashok Raj Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/genapic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c index f3159a496e39c..fe416fd4dbe0b 100644 --- a/arch/x86_64/kernel/genapic.c +++ b/arch/x86_64/kernel/genapic.c @@ -72,7 +72,7 @@ void __init clustered_apic_check(void) /* Don't use clustered mode on AMD platforms. */ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { genapic = &apic_physflat; -#ifndef CONFIG_CPU_HOTPLUG +#ifndef CONFIG_HOTPLUG_CPU /* In the CPU hotplug case we cannot use broadcast mode because that opens a race when a CPU is removed. Stay at physflat mode in this case. -- GitLab From 47e5701e37cf10948c3f2952870d9f18b6e84965 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 537/563] [PATCH] x86-64: Remove freeing of SMP trampoline pages Nick points out it never worked because PageReserved was set and it might cause problems later on. Also HOTPLUG_CPU is much more common now so let's care not too much about the !hotplug case. Cc: nickpiggin@yahoo.com.au Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/smpboot.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 277ce5e91e04d..5b7aadbef5f99 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -859,17 +859,6 @@ static __cpuinit void smp_cleanup_boot(void) * Reset trampoline flag */ *((volatile int *) phys_to_virt(0x467)) = 0; - -#ifndef CONFIG_HOTPLUG_CPU - /* - * Free pages reserved for SMP bootup. - * When you add hotplug CPU support later remove this - * Note there is more work to be done for later CPU bootup. - */ - - free_page((unsigned long) __va(PAGE_SIZE)); - free_page((unsigned long) __va(SMP_TRAMPOLINE_BASE)); -#endif } /* -- GitLab From 9c0aa0f9a16557a3dd9b7b0d39bc67ddf1fa0b32 Mon Sep 17 00:00:00 2001 From: Adrian Bunk <bunk@stusta.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 538/563] [PATCH] Replace extern inline with static inline in asm-x86_64/* They should be identical in the kernel now, but this makes it consistent with other code. Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-x86_64/desc.h | 2 +- include/asm-x86_64/fixmap.h | 2 +- include/asm-x86_64/io.h | 14 +++++++------- include/asm-x86_64/msr.h | 10 +++++----- include/asm-x86_64/pgalloc.h | 8 ++++---- include/asm-x86_64/pgtable.h | 6 +++--- include/asm-x86_64/processor.h | 4 ++-- include/asm-x86_64/signal.h | 10 +++++----- include/asm-x86_64/smp.h | 2 +- include/asm-x86_64/system.h | 2 +- 10 files changed, 30 insertions(+), 30 deletions(-) diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h index c89b58bebee24..594e610f4a1e7 100644 --- a/include/asm-x86_64/desc.h +++ b/include/asm-x86_64/desc.h @@ -191,7 +191,7 @@ static inline void load_TLS(struct thread_struct *t, unsigned int cpu) /* * load one particular LDT into the current CPU */ -extern inline void load_LDT_nolock (mm_context_t *pc, int cpu) +static inline void load_LDT_nolock (mm_context_t *pc, int cpu) { int count = pc->size; diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h index cf8b16cbe8db6..a582cfcf2231a 100644 --- a/include/asm-x86_64/fixmap.h +++ b/include/asm-x86_64/fixmap.h @@ -76,7 +76,7 @@ extern void __this_fixmap_does_not_exist(void); * directly without translation, we catch the bug with a NULL-deference * kernel oops. Illegal ranges of incoming indices are caught too. */ -extern inline unsigned long fix_to_virt(const unsigned int idx) +static inline unsigned long fix_to_virt(const unsigned int idx) { /* * this branch gets completely eliminated after inlining, diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h index 37fc3f149a5a6..52ff269fe0547 100644 --- a/include/asm-x86_64/io.h +++ b/include/asm-x86_64/io.h @@ -48,7 +48,7 @@ * Talk about misusing macros.. */ #define __OUT1(s,x) \ -extern inline void out##s(unsigned x value, unsigned short port) { +static inline void out##s(unsigned x value, unsigned short port) { #define __OUT2(s,s1,s2) \ __asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" @@ -58,7 +58,7 @@ __OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \ __OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \ #define __IN1(s) \ -extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; +static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; #define __IN2(s,s1,s2) \ __asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" @@ -68,12 +68,12 @@ __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ __IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \ #define __INS(s) \ -extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \ +static inline void ins##s(unsigned short port, void * addr, unsigned long count) \ { __asm__ __volatile__ ("rep ; ins" #s \ : "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } #define __OUTS(s) \ -extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ +static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ { __asm__ __volatile__ ("rep ; outs" #s \ : "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } @@ -110,12 +110,12 @@ __OUTS(l) * Change virtual addresses to physical addresses and vv. * These are pretty trivial */ -extern inline unsigned long virt_to_phys(volatile void * address) +static inline unsigned long virt_to_phys(volatile void * address) { return __pa(address); } -extern inline void * phys_to_virt(unsigned long address) +static inline void * phys_to_virt(unsigned long address) { return __va(address); } @@ -130,7 +130,7 @@ extern inline void * phys_to_virt(unsigned long address) extern void __iomem *__ioremap(unsigned long offset, unsigned long size, unsigned long flags); -extern inline void __iomem * ioremap (unsigned long offset, unsigned long size) +static inline void __iomem * ioremap (unsigned long offset, unsigned long size) { return __ioremap(offset, size, 0); } diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h index ba15279a79d02..15a6ef7cf3d32 100644 --- a/include/asm-x86_64/msr.h +++ b/include/asm-x86_64/msr.h @@ -64,7 +64,7 @@ : "=a" (low), "=d" (high) \ : "c" (counter)) -extern inline void cpuid(int op, unsigned int *eax, unsigned int *ebx, +static inline void cpuid(int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { __asm__("cpuid" @@ -90,7 +90,7 @@ static inline void cpuid_count(int op, int count, int *eax, int *ebx, int *ecx, /* * CPUID functions returning a single datum */ -extern inline unsigned int cpuid_eax(unsigned int op) +static inline unsigned int cpuid_eax(unsigned int op) { unsigned int eax; @@ -100,7 +100,7 @@ extern inline unsigned int cpuid_eax(unsigned int op) : "bx", "cx", "dx"); return eax; } -extern inline unsigned int cpuid_ebx(unsigned int op) +static inline unsigned int cpuid_ebx(unsigned int op) { unsigned int eax, ebx; @@ -110,7 +110,7 @@ extern inline unsigned int cpuid_ebx(unsigned int op) : "cx", "dx" ); return ebx; } -extern inline unsigned int cpuid_ecx(unsigned int op) +static inline unsigned int cpuid_ecx(unsigned int op) { unsigned int eax, ecx; @@ -120,7 +120,7 @@ extern inline unsigned int cpuid_ecx(unsigned int op) : "bx", "dx" ); return ecx; } -extern inline unsigned int cpuid_edx(unsigned int op) +static inline unsigned int cpuid_edx(unsigned int op) { unsigned int eax, edx; diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h index deadd146978b1..08cad2482bcbc 100644 --- a/include/asm-x86_64/pgalloc.h +++ b/include/asm-x86_64/pgalloc.h @@ -18,12 +18,12 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *p set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT))); } -extern __inline__ pmd_t *get_pmd(void) +static inline pmd_t *get_pmd(void) { return (pmd_t *)get_zeroed_page(GFP_KERNEL); } -extern __inline__ void pmd_free(pmd_t *pmd) +static inline void pmd_free(pmd_t *pmd) { BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); free_page((unsigned long)pmd); @@ -86,13 +86,13 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long add /* Should really implement gc for free page table pages. This could be done with a reference count in struct page. */ -extern __inline__ void pte_free_kernel(pte_t *pte) +static inline void pte_free_kernel(pte_t *pte) { BUG_ON((unsigned long)pte & (PAGE_SIZE-1)); free_page((unsigned long)pte); } -extern inline void pte_free(struct page *pte) +static inline void pte_free(struct page *pte) { __free_page(pte); } diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h index 5e0f2fdab0d35..1dc110ba82d63 100644 --- a/include/asm-x86_64/pgtable.h +++ b/include/asm-x86_64/pgtable.h @@ -85,7 +85,7 @@ static inline void set_pud(pud_t *dst, pud_t val) pud_val(*dst) = pud_val(val); } -extern inline void pud_clear (pud_t *pud) +static inline void pud_clear (pud_t *pud) { set_pud(pud, __pud(0)); } @@ -95,7 +95,7 @@ static inline void set_pgd(pgd_t *dst, pgd_t val) pgd_val(*dst) = pgd_val(val); } -extern inline void pgd_clear (pgd_t * pgd) +static inline void pgd_clear (pgd_t * pgd) { set_pgd(pgd, __pgd(0)); } @@ -375,7 +375,7 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) } /* Change flags of a PTE */ -extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte_val(pte) &= _PAGE_CHG_MASK; pte_val(pte) |= pgprot_val(newprot); diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h index a8321999448f8..c6461c16edbf9 100644 --- a/include/asm-x86_64/processor.h +++ b/include/asm-x86_64/processor.h @@ -375,13 +375,13 @@ struct extended_sigtable { #define ASM_NOP_MAX 8 /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ -extern inline void rep_nop(void) +static inline void rep_nop(void) { __asm__ __volatile__("rep;nop": : :"memory"); } /* Stop speculative execution */ -extern inline void sync_core(void) +static inline void sync_core(void) { int tmp; asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory"); diff --git a/include/asm-x86_64/signal.h b/include/asm-x86_64/signal.h index fe9b96d94815f..f8d55798535ac 100644 --- a/include/asm-x86_64/signal.h +++ b/include/asm-x86_64/signal.h @@ -143,23 +143,23 @@ typedef struct sigaltstack { #undef __HAVE_ARCH_SIG_BITOPS #if 0 -extern __inline__ void sigaddset(sigset_t *set, int _sig) +static inline void sigaddset(sigset_t *set, int _sig) { __asm__("btsq %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); } -extern __inline__ void sigdelset(sigset_t *set, int _sig) +static inline void sigdelset(sigset_t *set, int _sig) { __asm__("btrq %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); } -extern __inline__ int __const_sigismember(sigset_t *set, int _sig) +static inline int __const_sigismember(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; return 1 & (set->sig[sig / _NSIG_BPW] >> (sig & ~(_NSIG_BPW-1))); } -extern __inline__ int __gen_sigismember(sigset_t *set, int _sig) +static inline int __gen_sigismember(sigset_t *set, int _sig) { int ret; __asm__("btq %2,%1\n\tsbbq %0,%0" @@ -172,7 +172,7 @@ extern __inline__ int __gen_sigismember(sigset_t *set, int _sig) __const_sigismember((set),(sig)) : \ __gen_sigismember((set),(sig))) -extern __inline__ int sigfindinword(unsigned long word) +static inline int sigfindinword(unsigned long word) { __asm__("bsfq %1,%0" : "=r"(word) : "rm"(word) : "cc"); return word; diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h index de8b57b2b62b9..24e32611f0bf3 100644 --- a/include/asm-x86_64/smp.h +++ b/include/asm-x86_64/smp.h @@ -72,7 +72,7 @@ static inline int num_booting_cpus(void) #define raw_smp_processor_id() read_pda(cpunumber) -extern __inline int hard_smp_processor_id(void) +static inline int hard_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID)); diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h index 8606e170a7dc8..d65381194bda3 100644 --- a/include/asm-x86_64/system.h +++ b/include/asm-x86_64/system.h @@ -188,7 +188,7 @@ static inline void write_cr4(unsigned long val) #define __xg(x) ((volatile long *)(x)) -extern inline void set_64bit(volatile unsigned long *ptr, unsigned long val) +static inline void set_64bit(volatile unsigned long *ptr, unsigned long val) { *ptr = val; } -- GitLab From c1a71a1ede8f743209237b2736893f3aebe13bb0 Mon Sep 17 00:00:00 2001 From: Ashok Raj <ashok.raj@intel.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 539/563] [PATCH] x86-64: Delivery mode should be APIC_DM_FIXED when using physical mode. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/genapic_flat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c index 8c6028a0f322f..9da3edb799ea5 100644 --- a/arch/x86_64/kernel/genapic_flat.c +++ b/arch/x86_64/kernel/genapic_flat.c @@ -177,9 +177,9 @@ static unsigned int physflat_cpu_mask_to_apicid(cpumask_t cpumask) struct genapic apic_physflat = { .name = "physical flat", - .int_delivery_mode = dest_LowestPrio, + .int_delivery_mode = dest_Fixed, .int_dest_mode = (APIC_DEST_PHYSICAL != 0), - .int_delivery_dest = APIC_DEST_PHYSICAL | APIC_DM_LOWEST, + .int_delivery_dest = APIC_DEST_PHYSICAL | APIC_DM_FIXED, .target_cpus = physflat_target_cpus, .apic_id_registered = flat_apic_id_registered, .init_apic_ldr = flat_init_apic_ldr,/*not needed, but shouldn't hurt*/ -- GitLab From 2e8ad43ec07545780ce7992cb18e2d82c7abd24c Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 540/563] [PATCH] x86-64: Prevent gcc 4 from optimizing away vsyscalls They were previously static. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/vsyscall.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index 2e57344259496..70a0bd16085fb 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -107,7 +107,7 @@ static force_inline long time_syscall(long *t) return secs; } -static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) +int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) { if (unlikely(!__sysctl_vsyscall)) return gettimeofday(tv,tz); @@ -120,7 +120,7 @@ static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz /* This will break when the xtime seconds get inaccurate, but that is * unlikely */ -static time_t __vsyscall(1) vtime(time_t *t) +time_t __vsyscall(1) vtime(time_t *t) { if (unlikely(!__sysctl_vsyscall)) return time_syscall(t); @@ -129,12 +129,12 @@ static time_t __vsyscall(1) vtime(time_t *t) return __xtime.tv_sec; } -static long __vsyscall(2) venosys_0(void) +long __vsyscall(2) venosys_0(void) { return -ENOSYS; } -static long __vsyscall(3) venosys_1(void) +long __vsyscall(3) venosys_1(void) { return -ENOSYS; } -- GitLab From 05d1fa4bf6a1528e4d4e39fa537f11e6cfca4720 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 541/563] [PATCH] x86-64: Improve error handling for overlapping PXMs in SRAT. - Report PXMs instead of nodes - Report the correct PXM, not always the one of node 1. - Only warn for the case of a PXM overlapping by itself Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/mm/srat.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index db6b073a149ff..36bc7be9afb98 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -25,6 +25,8 @@ static nodemask_t nodes_found __initdata; static struct node nodes[MAX_NUMNODES] __initdata; static __u8 pxm2node[256] = { [0 ... 255] = 0xff }; +static int node_to_pxm(int n); + int pxm_to_node(int pxm) { if ((unsigned)pxm >= 256) @@ -53,9 +55,9 @@ static __init int conflicting_nodes(unsigned long start, unsigned long end) if (nd->start == nd->end) continue; if (nd->end > start && nd->start < end) - return 1; + return i; if (nd->end == end && nd->start == start) - return 1; + return i; } return -1; } @@ -139,10 +141,15 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) printk(KERN_INFO "SRAT: hot plug zone found %lx - %lx \n", start, end); i = conflicting_nodes(start, end); - if (i >= 0) { + if (i == node) { + printk(KERN_WARNING + "SRAT: Warning: PXM %d (%lx-%lx) overlaps with itself (%Lx-%Lx)\n", + pxm, start, end, nodes[i].start, nodes[i].end); + } else if (i >= 0) { printk(KERN_ERR - "SRAT: pxm %d overlap %lx-%lx with node %d(%Lx-%Lx)\n", - pxm, start, end, i, nodes[i].start, nodes[i].end); + "SRAT: PXM %d (%lx-%lx) overlaps with PXM %d (%Lx-%Lx)\n", + pxm, start, end, node_to_pxm(i), + nodes[i].start, nodes[i].end); bad_srat(); return; } @@ -197,7 +204,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) return 0; } -int node_to_pxm(int n) +static int node_to_pxm(int n) { int i; if (pxm2node[n] == n) -- GitLab From 27183ebd330a676fe29f7eb9b7ff582492246ec8 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 542/563] [PATCH] x86-64: Add dma_sync_single_range_for_{cpu,device} Currently just defined to their non range parts. Pointed out by John Linville Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-x86_64/dma-mapping.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h index a416dc31634a2..e784fdc524f1a 100644 --- a/include/asm-x86_64/dma-mapping.h +++ b/include/asm-x86_64/dma-mapping.h @@ -85,6 +85,11 @@ static inline void dma_sync_single_for_device(struct device *hwdev, flush_write_buffers(); } +#define dma_sync_single_range_for_cpu(dev, dma_handle, offset, size, dir) \ + dma_sync_single_for_cpu(dev, dma_handle, size, dir) +#define dma_sync_single_range_for_device(dev, dma_handle, offset, size, dir) \ + dma_sync_single_for_device(dev, dma_handle, size, dir) + static inline void dma_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg, int nelems, int direction) -- GitLab From 5bf97e01192f0fcdff2f0e9eae063e7785f6f915 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 543/563] [PATCH] x86-64: Use physflat on Intel for < 8 CPUs with CPU hotplug This avoids races with the APIC broadcast/mask modes. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/genapic.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c index fe416fd4dbe0b..7a64ea181788c 100644 --- a/arch/x86_64/kernel/genapic.c +++ b/arch/x86_64/kernel/genapic.c @@ -104,9 +104,14 @@ void __init clustered_apic_check(void) * (We don't use lowest priority delivery + HW APIC IRQ steering, so * can ignore the clustered logical case and go straight to physical.) */ - if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) + if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) { +#ifdef CONFIG_HOTPLUG_CPU + /* Don't use APIC shortcuts in CPU hotplug to avoid races */ + genapic = &apic_physflat; +#else genapic = &apic_flat; - else +#endif + } else genapic = &apic_cluster; print: -- GitLab From b3ab8382245541ea030faaa1645f66258fde452d Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 544/563] [PATCH] x86-64: Fix gcc 4 warnings about pointer signedness Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/boot/compressed/misc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c index b38d5b8b5fb84..0e10fd84c7cc7 100644 --- a/arch/x86_64/boot/compressed/misc.c +++ b/arch/x86_64/boot/compressed/misc.c @@ -83,7 +83,7 @@ static unsigned char *real_mode; /* Pointer to real-mode data */ #endif #define SCREEN_INFO (*(struct screen_info *)(real_mode+0)) -extern char input_data[]; +extern unsigned char input_data[]; extern int input_len; static long bytes_out = 0; @@ -288,7 +288,7 @@ void setup_normal_output_buffer(void) #else if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory"); #endif - output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */ + output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */ free_mem_end_ptr = (long)real_mode; } @@ -305,7 +305,7 @@ void setup_output_buffer_if_we_run_high(struct moveparams *mv) #else if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory"); #endif - mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START; + mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START; low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff; low_buffer_size = low_buffer_end - LOW_BUFFER_START; -- GitLab From 7effaa882af523085f7acadc5871b75a7e506baf Mon Sep 17 00:00:00 2001 From: Jan Beulich <jbeulich@novell.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 545/563] [PATCH] x86-64: Fix CFI information Being the foundation for reliable stack unwinding, this fixes CFI unwind annotations in many low-level x86_64 routines, plus a config option (available to all architectures, and also present in the previously sent patch adding such annotations to i386 code) to enable them separatly rather than only along with adding full debug information. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/ia32/ia32entry.S | 51 ++++++++- arch/x86_64/kernel/entry.S | 207 +++++++++++++++++++++++++---------- include/asm-x86_64/calling.h | 23 ++-- include/asm-x86_64/dwarf2.h | 8 ++ 4 files changed, 220 insertions(+), 69 deletions(-) diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index 5244f803203d6..e0eb0c712fe91 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -55,20 +55,34 @@ * with the int 0x80 path. */ ENTRY(ia32_sysenter_target) - CFI_STARTPROC + CFI_STARTPROC simple + CFI_DEF_CFA rsp,0 + CFI_REGISTER rsp,rbp swapgs movq %gs:pda_kernelstack, %rsp addq $(PDA_STACKOFFSET),%rsp sti movl %ebp,%ebp /* zero extension */ pushq $__USER32_DS + CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET ss,0*/ pushq %rbp + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rsp,0 pushfq + CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET rflags,0*/ movl $VSYSCALL32_SYSEXIT, %r10d + CFI_REGISTER rip,r10 pushq $__USER32_CS + CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET cs,0*/ movl %eax, %eax pushq %r10 + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rip,0 pushq %rax + CFI_ADJUST_CFA_OFFSET 8 cld SAVE_ARGS 0,0,1 /* no need to do an access_ok check here because rbp has been @@ -79,6 +93,7 @@ ENTRY(ia32_sysenter_target) .previous GET_THREAD_INFO(%r10) testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10) + CFI_REMEMBER_STATE jnz sysenter_tracesys sysenter_do_call: cmpl $(IA32_NR_syscalls),%eax @@ -94,14 +109,20 @@ sysenter_do_call: andl $~0x200,EFLAGS-R11(%rsp) RESTORE_ARGS 1,24,1,1,1,1 popfq + CFI_ADJUST_CFA_OFFSET -8 + /*CFI_RESTORE rflags*/ popq %rcx /* User %esp */ + CFI_ADJUST_CFA_OFFSET -8 + CFI_REGISTER rsp,rcx movl $VSYSCALL32_SYSEXIT,%edx /* User %eip */ + CFI_REGISTER rip,rdx swapgs sti /* sti only takes effect after the next instruction */ /* sysexit */ .byte 0xf, 0x35 sysenter_tracesys: + CFI_RESTORE_STATE SAVE_REST CLEAR_RREGS movq $-ENOSYS,RAX(%rsp) /* really needed? */ @@ -140,21 +161,28 @@ sysenter_tracesys: * with the int 0x80 path. */ ENTRY(ia32_cstar_target) - CFI_STARTPROC + CFI_STARTPROC simple + CFI_DEF_CFA rsp,0 + CFI_REGISTER rip,rcx + /*CFI_REGISTER rflags,r11*/ swapgs movl %esp,%r8d + CFI_REGISTER rsp,r8 movq %gs:pda_kernelstack,%rsp sti SAVE_ARGS 8,1,1 movl %eax,%eax /* zero extension */ movq %rax,ORIG_RAX-ARGOFFSET(%rsp) movq %rcx,RIP-ARGOFFSET(%rsp) + CFI_REL_OFFSET rip,RIP-ARGOFFSET movq %rbp,RCX-ARGOFFSET(%rsp) /* this lies slightly to ptrace */ movl %ebp,%ecx movq $__USER32_CS,CS-ARGOFFSET(%rsp) movq $__USER32_DS,SS-ARGOFFSET(%rsp) movq %r11,EFLAGS-ARGOFFSET(%rsp) + /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/ movq %r8,RSP-ARGOFFSET(%rsp) + CFI_REL_OFFSET rsp,RSP-ARGOFFSET /* no need to do an access_ok check here because r8 has been 32bit zero extended */ /* hardware stack frame is complete now */ @@ -164,6 +192,7 @@ ENTRY(ia32_cstar_target) .previous GET_THREAD_INFO(%r10) testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10) + CFI_REMEMBER_STATE jnz cstar_tracesys cstar_do_call: cmpl $IA32_NR_syscalls,%eax @@ -177,12 +206,16 @@ cstar_do_call: jnz int_ret_from_sys_call RESTORE_ARGS 1,-ARG_SKIP,1,1,1 movl RIP-ARGOFFSET(%rsp),%ecx + CFI_REGISTER rip,rcx movl EFLAGS-ARGOFFSET(%rsp),%r11d + /*CFI_REGISTER rflags,r11*/ movl RSP-ARGOFFSET(%rsp),%esp + CFI_RESTORE rsp swapgs sysretl cstar_tracesys: + CFI_RESTORE_STATE SAVE_REST CLEAR_RREGS movq $-ENOSYS,RAX(%rsp) /* really needed? */ @@ -226,11 +259,18 @@ ia32_badarg: */ ENTRY(ia32_syscall) - CFI_STARTPROC + CFI_STARTPROC simple + CFI_DEF_CFA rsp,SS+8-RIP + /*CFI_REL_OFFSET ss,SS-RIP*/ + CFI_REL_OFFSET rsp,RSP-RIP + /*CFI_REL_OFFSET rflags,EFLAGS-RIP*/ + /*CFI_REL_OFFSET cs,CS-RIP*/ + CFI_REL_OFFSET rip,RIP-RIP swapgs sti movl %eax,%eax pushq %rax + CFI_ADJUST_CFA_OFFSET 8 cld /* note the registers are not zero extended to the sf. this could be a problem. */ @@ -278,6 +318,8 @@ quiet_ni_syscall: jmp ia32_ptregs_common .endm + CFI_STARTPROC + PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx @@ -290,8 +332,9 @@ quiet_ni_syscall: PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend, %rdx ENTRY(ia32_ptregs_common) - CFI_STARTPROC popq %r11 + CFI_ADJUST_CFA_OFFSET -8 + CFI_REGISTER rip, r11 SAVE_REST call *%rax RESTORE_REST diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index 873c39d8f8184..7937971d1853b 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -79,16 +79,19 @@ xorl %eax, %eax pushq %rax /* ss */ CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET ss,0*/ pushq %rax /* rsp */ CFI_ADJUST_CFA_OFFSET 8 - CFI_OFFSET rip,0 + CFI_REL_OFFSET rsp,0 pushq $(1<<9) /* eflags - interrupts on */ CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET rflags,0*/ pushq $__KERNEL_CS /* cs */ CFI_ADJUST_CFA_OFFSET 8 + /*CFI_REL_OFFSET cs,0*/ pushq \child_rip /* rip */ CFI_ADJUST_CFA_OFFSET 8 - CFI_OFFSET rip,0 + CFI_REL_OFFSET rip,0 pushq %rax /* orig rax */ CFI_ADJUST_CFA_OFFSET 8 .endm @@ -98,32 +101,39 @@ CFI_ADJUST_CFA_OFFSET -(6*8) .endm - .macro CFI_DEFAULT_STACK - CFI_ADJUST_CFA_OFFSET (SS) - CFI_OFFSET r15,R15-SS - CFI_OFFSET r14,R14-SS - CFI_OFFSET r13,R13-SS - CFI_OFFSET r12,R12-SS - CFI_OFFSET rbp,RBP-SS - CFI_OFFSET rbx,RBX-SS - CFI_OFFSET r11,R11-SS - CFI_OFFSET r10,R10-SS - CFI_OFFSET r9,R9-SS - CFI_OFFSET r8,R8-SS - CFI_OFFSET rax,RAX-SS - CFI_OFFSET rcx,RCX-SS - CFI_OFFSET rdx,RDX-SS - CFI_OFFSET rsi,RSI-SS - CFI_OFFSET rdi,RDI-SS - CFI_OFFSET rsp,RSP-SS - CFI_OFFSET rip,RIP-SS + .macro CFI_DEFAULT_STACK start=1 + .if \start + CFI_STARTPROC simple + CFI_DEF_CFA rsp,SS+8 + .else + CFI_DEF_CFA_OFFSET SS+8 + .endif + CFI_REL_OFFSET r15,R15 + CFI_REL_OFFSET r14,R14 + CFI_REL_OFFSET r13,R13 + CFI_REL_OFFSET r12,R12 + CFI_REL_OFFSET rbp,RBP + CFI_REL_OFFSET rbx,RBX + CFI_REL_OFFSET r11,R11 + CFI_REL_OFFSET r10,R10 + CFI_REL_OFFSET r9,R9 + CFI_REL_OFFSET r8,R8 + CFI_REL_OFFSET rax,RAX + CFI_REL_OFFSET rcx,RCX + CFI_REL_OFFSET rdx,RDX + CFI_REL_OFFSET rsi,RSI + CFI_REL_OFFSET rdi,RDI + CFI_REL_OFFSET rip,RIP + /*CFI_REL_OFFSET cs,CS*/ + /*CFI_REL_OFFSET rflags,EFLAGS*/ + CFI_REL_OFFSET rsp,RSP + /*CFI_REL_OFFSET ss,SS*/ .endm /* * A newly forked process directly context switches into this. */ /* rdi: prev */ ENTRY(ret_from_fork) - CFI_STARTPROC CFI_DEFAULT_STACK call schedule_tail GET_THREAD_INFO(%rcx) @@ -172,16 +182,21 @@ rff_trace: */ ENTRY(system_call) - CFI_STARTPROC + CFI_STARTPROC simple + CFI_DEF_CFA rsp,0 + CFI_REGISTER rip,rcx + /*CFI_REGISTER rflags,r11*/ swapgs movq %rsp,%gs:pda_oldrsp movq %gs:pda_kernelstack,%rsp sti SAVE_ARGS 8,1 movq %rax,ORIG_RAX-ARGOFFSET(%rsp) - movq %rcx,RIP-ARGOFFSET(%rsp) + movq %rcx,RIP-ARGOFFSET(%rsp) + CFI_REL_OFFSET rip,RIP-ARGOFFSET GET_THREAD_INFO(%rcx) testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%rcx) + CFI_REMEMBER_STATE jnz tracesys cmpq $__NR_syscall_max,%rax ja badsys @@ -201,9 +216,12 @@ sysret_check: cli movl threadinfo_flags(%rcx),%edx andl %edi,%edx + CFI_REMEMBER_STATE jnz sysret_careful movq RIP-ARGOFFSET(%rsp),%rcx + CFI_REGISTER rip,rcx RESTORE_ARGS 0,-ARG_SKIP,1 + /*CFI_REGISTER rflags,r11*/ movq %gs:pda_oldrsp,%rsp swapgs sysretq @@ -211,12 +229,15 @@ sysret_check: /* Handle reschedules */ /* edx: work, edi: workmask */ sysret_careful: + CFI_RESTORE_STATE bt $TIF_NEED_RESCHED,%edx jnc sysret_signal sti pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 call schedule popq %rdi + CFI_ADJUST_CFA_OFFSET -8 jmp sysret_check /* Handle a signal */ @@ -234,8 +255,13 @@ sysret_signal: 1: movl $_TIF_NEED_RESCHED,%edi jmp sysret_check +badsys: + movq $-ENOSYS,RAX-ARGOFFSET(%rsp) + jmp ret_from_sys_call + /* Do syscall tracing */ tracesys: + CFI_RESTORE_STATE SAVE_REST movq $-ENOSYS,RAX(%rsp) FIXUP_TOP_OF_STACK %rdi @@ -254,16 +280,29 @@ tracesys: RESTORE_TOP_OF_STACK %rbx RESTORE_REST jmp ret_from_sys_call + CFI_ENDPROC -badsys: - movq $-ENOSYS,RAX-ARGOFFSET(%rsp) - jmp ret_from_sys_call - /* * Syscall return path ending with IRET. * Has correct top of stack, but partial stack frame. */ -ENTRY(int_ret_from_sys_call) +ENTRY(int_ret_from_sys_call) + CFI_STARTPROC simple + CFI_DEF_CFA rsp,SS+8-ARGOFFSET + /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/ + CFI_REL_OFFSET rsp,RSP-ARGOFFSET + /*CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/ + /*CFI_REL_OFFSET cs,CS-ARGOFFSET*/ + CFI_REL_OFFSET rip,RIP-ARGOFFSET + CFI_REL_OFFSET rdx,RDX-ARGOFFSET + CFI_REL_OFFSET rcx,RCX-ARGOFFSET + CFI_REL_OFFSET rax,RAX-ARGOFFSET + CFI_REL_OFFSET rdi,RDI-ARGOFFSET + CFI_REL_OFFSET rsi,RSI-ARGOFFSET + CFI_REL_OFFSET r8,R8-ARGOFFSET + CFI_REL_OFFSET r9,R9-ARGOFFSET + CFI_REL_OFFSET r10,R10-ARGOFFSET + CFI_REL_OFFSET r11,R11-ARGOFFSET cli testl $3,CS-ARGOFFSET(%rsp) je retint_restore_args @@ -284,8 +323,10 @@ int_careful: jnc int_very_careful sti pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 call schedule popq %rdi + CFI_ADJUST_CFA_OFFSET -8 cli jmp int_with_check @@ -297,9 +338,11 @@ int_very_careful: testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edx jz int_signal pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 leaq 8(%rsp),%rdi # &ptregs -> arg1 call syscall_trace_leave popq %rdi + CFI_ADJUST_CFA_OFFSET -8 andl $~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP),%edi cli jmp int_restore_rest @@ -329,6 +372,8 @@ int_restore_rest: jmp ptregscall_common .endm + CFI_STARTPROC + PTREGSCALL stub_clone, sys_clone, %r8 PTREGSCALL stub_fork, sys_fork, %rdi PTREGSCALL stub_vfork, sys_vfork, %rdi @@ -337,40 +382,49 @@ int_restore_rest: PTREGSCALL stub_iopl, sys_iopl, %rsi ENTRY(ptregscall_common) - CFI_STARTPROC popq %r11 - CFI_ADJUST_CFA_OFFSET -8 + CFI_ADJUST_CFA_OFFSET -8 + CFI_REGISTER rip, r11 SAVE_REST movq %r11, %r15 + CFI_REGISTER rip, r15 FIXUP_TOP_OF_STACK %r11 call *%rax RESTORE_TOP_OF_STACK %r11 movq %r15, %r11 + CFI_REGISTER rip, r11 RESTORE_REST pushq %r11 - CFI_ADJUST_CFA_OFFSET 8 + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rip, 0 ret CFI_ENDPROC ENTRY(stub_execve) CFI_STARTPROC popq %r11 - CFI_ADJUST_CFA_OFFSET -8 + CFI_ADJUST_CFA_OFFSET -8 + CFI_REGISTER rip, r11 SAVE_REST movq %r11, %r15 + CFI_REGISTER rip, r15 FIXUP_TOP_OF_STACK %r11 call sys_execve GET_THREAD_INFO(%rcx) bt $TIF_IA32,threadinfo_flags(%rcx) + CFI_REMEMBER_STATE jc exec_32bit RESTORE_TOP_OF_STACK %r11 movq %r15, %r11 + CFI_REGISTER rip, r11 RESTORE_REST - push %r11 + pushq %r11 + CFI_ADJUST_CFA_OFFSET 8 + CFI_REL_OFFSET rip, 0 ret exec_32bit: - CFI_ADJUST_CFA_OFFSET REST_SKIP + CFI_RESTORE_STATE movq %rax,RAX(%rsp) RESTORE_REST jmp int_ret_from_sys_call @@ -382,7 +436,8 @@ exec_32bit: */ ENTRY(stub_rt_sigreturn) CFI_STARTPROC - addq $8, %rsp + addq $8, %rsp + CFI_ADJUST_CFA_OFFSET -8 SAVE_REST movq %rsp,%rdi FIXUP_TOP_OF_STACK %r11 @@ -392,6 +447,25 @@ ENTRY(stub_rt_sigreturn) jmp int_ret_from_sys_call CFI_ENDPROC +/* + * initial frame state for interrupts and exceptions + */ + .macro _frame ref + CFI_STARTPROC simple + CFI_DEF_CFA rsp,SS+8-\ref + /*CFI_REL_OFFSET ss,SS-\ref*/ + CFI_REL_OFFSET rsp,RSP-\ref + /*CFI_REL_OFFSET rflags,EFLAGS-\ref*/ + /*CFI_REL_OFFSET cs,CS-\ref*/ + CFI_REL_OFFSET rip,RIP-\ref + .endm + +/* initial frame state for interrupts (and exceptions without error code) */ +#define INTR_FRAME _frame RIP +/* initial frame state for exceptions with error code (and interrupts with + vector already pushed) */ +#define XCPT_FRAME _frame ORIG_RAX + /* * Interrupt entry/exit. * @@ -402,10 +476,6 @@ ENTRY(stub_rt_sigreturn) /* 0(%rsp): interrupt number */ .macro interrupt func - CFI_STARTPROC simple - CFI_DEF_CFA rsp,(SS-RDI) - CFI_REL_OFFSET rsp,(RSP-ORIG_RAX) - CFI_REL_OFFSET rip,(RIP-ORIG_RAX) cld #ifdef CONFIG_DEBUG_INFO SAVE_ALL @@ -425,23 +495,27 @@ ENTRY(stub_rt_sigreturn) swapgs 1: incl %gs:pda_irqcount # RED-PEN should check preempt count movq %gs:pda_irqstackptr,%rax - cmoveq %rax,%rsp + cmoveq %rax,%rsp /*todo This needs CFI annotation! */ pushq %rdi # save old stack + CFI_ADJUST_CFA_OFFSET 8 call \func .endm ENTRY(common_interrupt) + XCPT_FRAME interrupt do_IRQ /* 0(%rsp): oldrsp-ARGOFFSET */ -ret_from_intr: +ret_from_intr: popq %rdi + CFI_ADJUST_CFA_OFFSET -8 cli decl %gs:pda_irqcount #ifdef CONFIG_DEBUG_INFO movq RBP(%rdi),%rbp + CFI_DEF_CFA_REGISTER rsp #endif - leaq ARGOFFSET(%rdi),%rsp -exit_intr: + leaq ARGOFFSET(%rdi),%rsp /*todo This needs CFI annotation! */ +exit_intr: GET_THREAD_INFO(%rcx) testl $3,CS-ARGOFFSET(%rsp) je retint_kernel @@ -453,9 +527,10 @@ exit_intr: */ retint_with_reschedule: movl $_TIF_WORK_MASK,%edi -retint_check: +retint_check: movl threadinfo_flags(%rcx),%edx andl %edi,%edx + CFI_REMEMBER_STATE jnz retint_careful retint_swapgs: swapgs @@ -476,14 +551,17 @@ bad_iret: jmp do_exit .previous - /* edi: workmask, edx: work */ + /* edi: workmask, edx: work */ retint_careful: + CFI_RESTORE_STATE bt $TIF_NEED_RESCHED,%edx jnc retint_signal sti pushq %rdi + CFI_ADJUST_CFA_OFFSET 8 call schedule popq %rdi + CFI_ADJUST_CFA_OFFSET -8 GET_THREAD_INFO(%rcx) cli jmp retint_check @@ -523,7 +601,9 @@ retint_kernel: * APIC interrupts. */ .macro apicinterrupt num,func + INTR_FRAME pushq $\num-256 + CFI_ADJUST_CFA_OFFSET 8 interrupt \func jmp ret_from_intr CFI_ENDPROC @@ -569,16 +649,23 @@ ENTRY(spurious_interrupt) * Exception entry points. */ .macro zeroentry sym + INTR_FRAME pushq $0 /* push error code/oldrax */ + CFI_ADJUST_CFA_OFFSET 8 pushq %rax /* push real oldrax to the rdi slot */ + CFI_ADJUST_CFA_OFFSET 8 leaq \sym(%rip),%rax jmp error_entry + CFI_ENDPROC .endm .macro errorentry sym + XCPT_FRAME pushq %rax + CFI_ADJUST_CFA_OFFSET 8 leaq \sym(%rip),%rax jmp error_entry + CFI_ENDPROC .endm /* error code is on the stack already */ @@ -605,10 +692,7 @@ ENTRY(spurious_interrupt) * and the exception handler in %rax. */ ENTRY(error_entry) - CFI_STARTPROC simple - CFI_DEF_CFA rsp,(SS-RDI) - CFI_REL_OFFSET rsp,(RSP-RDI) - CFI_REL_OFFSET rip,(RIP-RDI) + _frame RDI /* rdi slot contains rax, oldrax contains error code */ cld subq $14*8,%rsp @@ -690,7 +774,9 @@ error_kernelspace: /* Reload gs selector with exception handling */ /* edi: new selector */ ENTRY(load_gs_index) + CFI_STARTPROC pushf + CFI_ADJUST_CFA_OFFSET 8 cli swapgs gs_change: @@ -698,7 +784,9 @@ gs_change: 2: mfence /* workaround */ swapgs popf + CFI_ADJUST_CFA_OFFSET -8 ret + CFI_ENDPROC .section __ex_table,"a" .align 8 @@ -810,7 +898,7 @@ ENTRY(device_not_available) /* runs on exception stack */ KPROBE_ENTRY(debug) - CFI_STARTPROC + INTR_FRAME pushq $0 CFI_ADJUST_CFA_OFFSET 8 paranoidentry do_debug @@ -820,9 +908,9 @@ KPROBE_ENTRY(debug) /* runs on exception stack */ ENTRY(nmi) - CFI_STARTPROC + INTR_FRAME pushq $-1 - CFI_ADJUST_CFA_OFFSET 8 + CFI_ADJUST_CFA_OFFSET 8 paranoidentry do_nmi /* * "Paranoid" exit path from exception stack. @@ -888,7 +976,7 @@ ENTRY(reserved) /* runs on exception stack */ ENTRY(double_fault) - CFI_STARTPROC + XCPT_FRAME paranoidentry do_double_fault jmp paranoid_exit CFI_ENDPROC @@ -901,7 +989,7 @@ ENTRY(segment_not_present) /* runs on exception stack */ ENTRY(stack_segment) - CFI_STARTPROC + XCPT_FRAME paranoidentry do_stack_segment jmp paranoid_exit CFI_ENDPROC @@ -922,7 +1010,7 @@ ENTRY(spurious_interrupt_bug) #ifdef CONFIG_X86_MCE /* runs on exception stack */ ENTRY(machine_check) - CFI_STARTPROC + INTR_FRAME pushq $0 CFI_ADJUST_CFA_OFFSET 8 paranoidentry do_machine_check @@ -934,14 +1022,19 @@ ENTRY(call_debug) zeroentry do_call_debug ENTRY(call_softirq) + CFI_STARTPROC movq %gs:pda_irqstackptr,%rax pushq %r15 + CFI_ADJUST_CFA_OFFSET 8 movq %rsp,%r15 + CFI_DEF_CFA_REGISTER r15 incl %gs:pda_irqcount cmove %rax,%rsp call __do_softirq movq %r15,%rsp + CFI_DEF_CFA_REGISTER rsp decl %gs:pda_irqcount popq %r15 + CFI_ADJUST_CFA_OFFSET -8 ret - + CFI_ENDPROC diff --git a/include/asm-x86_64/calling.h b/include/asm-x86_64/calling.h index 0bc12655fa5be..fc2c5a6c262a2 100644 --- a/include/asm-x86_64/calling.h +++ b/include/asm-x86_64/calling.h @@ -65,27 +65,36 @@ .if \skipr11 .else movq (%rsp),%r11 + CFI_RESTORE r11 .endif .if \skipr8910 .else movq 1*8(%rsp),%r10 + CFI_RESTORE r10 movq 2*8(%rsp),%r9 + CFI_RESTORE r9 movq 3*8(%rsp),%r8 + CFI_RESTORE r8 .endif .if \skiprax .else movq 4*8(%rsp),%rax + CFI_RESTORE rax .endif .if \skiprcx .else movq 5*8(%rsp),%rcx + CFI_RESTORE rcx .endif .if \skiprdx .else movq 6*8(%rsp),%rdx + CFI_RESTORE rdx .endif movq 7*8(%rsp),%rsi + CFI_RESTORE rsi movq 8*8(%rsp),%rdi + CFI_RESTORE rdi .if ARG_SKIP+\addskip > 0 addq $ARG_SKIP+\addskip,%rsp CFI_ADJUST_CFA_OFFSET -(ARG_SKIP+\addskip) @@ -124,11 +133,17 @@ .macro RESTORE_REST movq (%rsp),%r15 + CFI_RESTORE r15 movq 1*8(%rsp),%r14 + CFI_RESTORE r14 movq 2*8(%rsp),%r13 + CFI_RESTORE r13 movq 3*8(%rsp),%r12 + CFI_RESTORE r12 movq 4*8(%rsp),%rbp + CFI_RESTORE rbp movq 5*8(%rsp),%rbx + CFI_RESTORE rbx addq $REST_SKIP,%rsp CFI_ADJUST_CFA_OFFSET -(REST_SKIP) .endm @@ -146,11 +161,3 @@ .macro icebp .byte 0xf1 .endm - -#ifdef CONFIG_FRAME_POINTER -#define ENTER enter -#define LEAVE leave -#else -#define ENTER -#define LEAVE -#endif diff --git a/include/asm-x86_64/dwarf2.h b/include/asm-x86_64/dwarf2.h index afd4212e860bd..582757fc03655 100644 --- a/include/asm-x86_64/dwarf2.h +++ b/include/asm-x86_64/dwarf2.h @@ -24,6 +24,10 @@ #define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset #define CFI_OFFSET .cfi_offset #define CFI_REL_OFFSET .cfi_rel_offset +#define CFI_REGISTER .cfi_register +#define CFI_RESTORE .cfi_restore +#define CFI_REMEMBER_STATE .cfi_remember_state +#define CFI_RESTORE_STATE .cfi_restore_state #else @@ -36,6 +40,10 @@ #define CFI_ADJUST_CFA_OFFSET # #define CFI_OFFSET # #define CFI_REL_OFFSET # +#define CFI_REGISTER # +#define CFI_RESTORE # +#define CFI_REMEMBER_STATE # +#define CFI_RESTORE_STATE # #endif -- GitLab From 55679edb19f5ee1dcb0147afe2f198a10ef963f0 Mon Sep 17 00:00:00 2001 From: Al Viro <viro@ZenIV.linux.org.uk> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 546/563] [PATCH] x86-64: Clean up includes in arch/x86_64/kernel/suspend.c Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/suspend.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c index 0612640d91b1c..ebb9abf3ce6da 100644 --- a/arch/x86_64/kernel/suspend.c +++ b/arch/x86_64/kernel/suspend.c @@ -8,23 +8,8 @@ */ #include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/spinlock.h> -#include <linux/poll.h> -#include <linux/delay.h> -#include <linux/sysrq.h> -#include <linux/proc_fs.h> -#include <linux/irq.h> -#include <linux/pm.h> -#include <linux/device.h> +#include <linux/smp.h> #include <linux/suspend.h> -#include <asm/uaccess.h> -#include <asm/acpi.h> -#include <asm/tlbflush.h> -#include <asm/io.h> #include <asm/proto.h> struct saved_context saved_context; -- GitLab From 059bf0f6c33058680e4381f17d554baaa4f45d68 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 547/563] [PATCH] x86-64: Merge msr.c with i386 version The only difference was the inline assembly, so move that into asm/msr.h and merge with the i386 version. This adds some missing sysfs support code to x86-64. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/Makefile | 1 + arch/x86_64/kernel/msr.c | 279 ------------------------------------ include/asm-x86_64/msr.h | 39 +++-- 3 files changed, 28 insertions(+), 291 deletions(-) delete mode 100644 arch/x86_64/kernel/msr.c diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index 1579bdd0adcde..bcdd0a805fe70 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -46,3 +46,4 @@ microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o quirks-y += ../../i386/kernel/quirks.o i8237-y += ../../i386/kernel/i8237.o +msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o diff --git a/arch/x86_64/kernel/msr.c b/arch/x86_64/kernel/msr.c deleted file mode 100644 index 598953ab01543..0000000000000 --- a/arch/x86_64/kernel/msr.c +++ /dev/null @@ -1,279 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2000 H. Peter Anvin - All Rights Reserved - * - * 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, Inc., 675 Mass Ave, Cambridge MA 02139, - * USA; either version 2 of the License, or (at your option) any later - * version; incorporated herein by reference. - * - * ----------------------------------------------------------------------- */ - -/* - * msr.c - * - * x86 MSR access device - * - * This device is accessed by lseek() to the appropriate register number - * and then read/write in chunks of 8 bytes. A larger size means multiple - * reads or writes of the same register. - * - * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on - * an SMP box will direct the access to CPU %d. - */ - -#include <linux/module.h> -#include <linux/config.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/fcntl.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/major.h> -#include <linux/fs.h> - -#include <asm/processor.h> -#include <asm/msr.h> -#include <asm/uaccess.h> -#include <asm/system.h> - -/* Note: "err" is handled in a funny way below. Otherwise one version - of gcc or another breaks. */ - -static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) -{ - int err; - - asm volatile ("1: wrmsr\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl %4,%0\n" - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" " .quad 1b,3b\n" ".previous":"=&bDS" (err) - :"a"(eax), "d"(edx), "c"(reg), "i"(-EIO), "0"(0)); - - return err; -} - -static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) -{ - int err; - - asm volatile ("1: rdmsr\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl %4,%0\n" - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" - " .quad 1b,3b\n" - ".previous":"=&bDS" (err), "=a"(*eax), "=d"(*edx) - :"c"(reg), "i"(-EIO), "0"(0)); - - return err; -} - -#ifdef CONFIG_SMP - -struct msr_command { - int cpu; - int err; - u32 reg; - u32 data[2]; -}; - -static void msr_smp_wrmsr(void *cmd_block) -{ - struct msr_command *cmd = (struct msr_command *)cmd_block; - - if (cmd->cpu == smp_processor_id()) - cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]); -} - -static void msr_smp_rdmsr(void *cmd_block) -{ - struct msr_command *cmd = (struct msr_command *)cmd_block; - - if (cmd->cpu == smp_processor_id()) - cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); -} - -static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) -{ - struct msr_command cmd; - int ret; - - preempt_disable(); - if (cpu == smp_processor_id()) { - ret = wrmsr_eio(reg, eax, edx); - } else { - cmd.cpu = cpu; - cmd.reg = reg; - cmd.data[0] = eax; - cmd.data[1] = edx; - - smp_call_function(msr_smp_wrmsr, &cmd, 1, 1); - ret = cmd.err; - } - preempt_enable(); - return ret; -} - -static inline int do_rdmsr(int cpu, u32 reg, u32 * eax, u32 * edx) -{ - struct msr_command cmd; - int ret; - - preempt_disable(); - if (cpu == smp_processor_id()) { - ret = rdmsr_eio(reg, eax, edx); - } else { - cmd.cpu = cpu; - cmd.reg = reg; - - smp_call_function(msr_smp_rdmsr, &cmd, 1, 1); - - *eax = cmd.data[0]; - *edx = cmd.data[1]; - - ret = cmd.err; - } - preempt_enable(); - return ret; -} - -#else /* ! CONFIG_SMP */ - -static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) -{ - return wrmsr_eio(reg, eax, edx); -} - -static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) -{ - return rdmsr_eio(reg, eax, edx); -} - -#endif /* ! CONFIG_SMP */ - -static loff_t msr_seek(struct file *file, loff_t offset, int orig) -{ - loff_t ret = -EINVAL; - - lock_kernel(); - switch (orig) { - case 0: - file->f_pos = offset; - ret = file->f_pos; - break; - case 1: - file->f_pos += offset; - ret = file->f_pos; - } - unlock_kernel(); - return ret; -} - -static ssize_t msr_read(struct file *file, char __user * buf, - size_t count, loff_t * ppos) -{ - u32 __user *tmp = (u32 __user *) buf; - u32 data[2]; - size_t rv; - u32 reg = *ppos; - int cpu = iminor(file->f_dentry->d_inode); - int err; - - if (count % 8) - return -EINVAL; /* Invalid chunk size */ - - for (rv = 0; count; count -= 8) { - err = do_rdmsr(cpu, reg, &data[0], &data[1]); - if (err) - return err; - if (copy_to_user(tmp, &data, 8)) - return -EFAULT; - tmp += 2; - } - - return ((char __user *)tmp) - buf; -} - -static ssize_t msr_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - const u32 __user *tmp = (const u32 __user *)buf; - u32 data[2]; - size_t rv; - u32 reg = *ppos; - int cpu = iminor(file->f_dentry->d_inode); - int err; - - if (count % 8) - return -EINVAL; /* Invalid chunk size */ - - for (rv = 0; count; count -= 8) { - if (copy_from_user(&data, tmp, 8)) - return -EFAULT; - err = do_wrmsr(cpu, reg, data[0], data[1]); - if (err) - return err; - tmp += 2; - } - - return ((char __user *)tmp) - buf; -} - -static int msr_open(struct inode *inode, struct file *file) -{ - unsigned int cpu = iminor(file->f_dentry->d_inode); - struct cpuinfo_x86 *c = &(cpu_data)[cpu]; - - if (cpu >= NR_CPUS || !cpu_online(cpu)) - return -ENXIO; /* No such CPU */ - if (!cpu_has(c, X86_FEATURE_MSR)) - return -EIO; /* MSR not supported */ - - return 0; -} - -/* - * File operations we support - */ -static struct file_operations msr_fops = { - .owner = THIS_MODULE, - .llseek = msr_seek, - .read = msr_read, - .write = msr_write, - .open = msr_open, -}; - -static int __init msr_init(void) -{ - if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) { - printk(KERN_ERR "msr: unable to get major %d for msr\n", - MSR_MAJOR); - return -EBUSY; - } - - return 0; -} - -static void __exit msr_exit(void) -{ - unregister_chrdev(MSR_MAJOR, "cpu/msr"); -} - -module_init(msr_init); -module_exit(msr_exit) - -MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>"); -MODULE_DESCRIPTION("x86 generic MSR driver"); -MODULE_LICENSE("GPL"); diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h index 15a6ef7cf3d32..4d727f3f5550b 100644 --- a/include/asm-x86_64/msr.h +++ b/include/asm-x86_64/msr.h @@ -29,22 +29,37 @@ #define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32) /* wrmsr with exception handling */ -#define wrmsr_safe(msr,a,b) ({ int ret__; \ - asm volatile("2: wrmsr ; xorl %0,%0\n" \ - "1:\n\t" \ - ".section .fixup,\"ax\"\n\t" \ - "3: movl %4,%0 ; jmp 1b\n\t" \ - ".previous\n\t" \ - ".section __ex_table,\"a\"\n" \ - " .align 8\n\t" \ - " .quad 2b,3b\n\t" \ - ".previous" \ - : "=a" (ret__) \ - : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\ +#define wrmsr_safe(msr,a,b) ({ int ret__; \ + asm volatile("2: wrmsr ; xorl %0,%0\n" \ + "1:\n\t" \ + ".section .fixup,\"ax\"\n\t" \ + "3: movl %4,%0 ; jmp 1b\n\t" \ + ".previous\n\t" \ + ".section __ex_table,\"a\"\n" \ + " .align 8\n\t" \ + " .quad 2b,3b\n\t" \ + ".previous" \ + : "=a" (ret__) \ + : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT)); \ ret__; }) #define checking_wrmsrl(msr,val) wrmsr_safe(msr,(u32)(val),(u32)((val)>>32)) +#define rdmsr_safe(msr,a,b) \ + ({ int ret__; \ + asm volatile ("1: rdmsr\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %4,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 8\n" \ + " .quad 1b,3b\n" \ + ".previous":"=&bDS" (ret__), "=a"(a), "=d"(b)\ + :"c"(msr), "i"(-EIO), "0"(0)); \ + ret__; }) + #define rdtsc(low,high) \ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) -- GitLab From 1209140c3c70aaa32d1a0462d79557f2a44a4ef8 Mon Sep 17 00:00:00 2001 From: Jan Beulich <jbeulich@novell.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 548/563] [PATCH] x86-64: Safe interrupts in oops_begin/end Rather than blindly re-enabling interrupts in oops_end(), save their state in oope_begin() and then restore that state. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/traps.c | 37 +++++++++++++++++++++---------------- arch/x86_64/mm/fault.c | 10 ++++++---- include/asm-x86_64/kdebug.h | 4 ++-- include/asm-x86_64/proto.h | 3 --- 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index f238d6078a5a9..64a59cb49411a 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -343,30 +343,33 @@ void out_of_line_bug(void) static DEFINE_SPINLOCK(die_lock); static int die_owner = -1; -void oops_begin(void) +unsigned long oops_begin(void) { - int cpu = safe_smp_processor_id(); - /* racy, but better than risking deadlock. */ - local_irq_disable(); + int cpu = safe_smp_processor_id(); + unsigned long flags; + + /* racy, but better than risking deadlock. */ + local_irq_save(flags); if (!spin_trylock(&die_lock)) { if (cpu == die_owner) /* nested oops. should stop eventually */; else - spin_lock(&die_lock); + spin_lock(&die_lock); } - die_owner = cpu; + die_owner = cpu; console_verbose(); - bust_spinlocks(1); + bust_spinlocks(1); + return flags; } -void oops_end(void) +void oops_end(unsigned long flags) { die_owner = -1; - bust_spinlocks(0); - spin_unlock(&die_lock); + bust_spinlocks(0); + spin_unlock_irqrestore(&die_lock, flags); if (panic_on_oops) - panic("Oops"); -} + panic("Oops"); +} void __die(const char * str, struct pt_regs * regs, long err) { @@ -392,10 +395,11 @@ void __die(const char * str, struct pt_regs * regs, long err) void die(const char * str, struct pt_regs * regs, long err) { - oops_begin(); + unsigned long flags = oops_begin(); + handle_BUG(regs); __die(str, regs, err); - oops_end(); + oops_end(flags); do_exit(SIGSEGV); } static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) @@ -406,7 +410,8 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e void die_nmi(char *str, struct pt_regs *regs) { - oops_begin(); + unsigned long flags = oops_begin(); + /* * We are in trouble anyway, lets at least try * to get a message out. @@ -416,7 +421,7 @@ void die_nmi(char *str, struct pt_regs *regs) if (panic_on_timeout || panic_on_oops) panic("nmi watchdog"); printk("console shuts up ...\n"); - oops_end(); + oops_end(flags); do_exit(SIGSEGV); } diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 816732d8858c3..b75b872ec154f 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -221,12 +221,13 @@ int unhandled_signal(struct task_struct *tsk, int sig) static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, unsigned long error_code) { - oops_begin(); + unsigned long flags = oops_begin(); + printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", current->comm, address); dump_pagetable(address); __die("Bad pagetable", regs, error_code); - oops_end(); + oops_end(flags); do_exit(SIGKILL); } @@ -304,6 +305,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long address; const struct exception_table_entry *fixup; int write; + unsigned long flags; siginfo_t info; #ifdef CONFIG_CHECKING @@ -521,7 +523,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, * terminate things with extreme prejudice. */ - oops_begin(); + flags = oops_begin(); if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); @@ -534,7 +536,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, __die("Oops", regs, error_code); /* Executive summary in case the body of the oops scrolled away */ printk(KERN_EMERG "CR2: %016lx\n", address); - oops_end(); + oops_end(flags); do_exit(SIGKILL); /* diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h index b90341994d80f..f604e84c53039 100644 --- a/include/asm-x86_64/kdebug.h +++ b/include/asm-x86_64/kdebug.h @@ -46,7 +46,7 @@ extern void die(const char *,struct pt_regs *,long); extern void __die(const char *,struct pt_regs *,long); extern void show_registers(struct pt_regs *regs); extern void dump_pagetable(unsigned long); -extern void oops_begin(void); -extern void oops_end(void); +extern unsigned long oops_begin(void); +extern void oops_end(unsigned long); #endif diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index 764b5f822ce28..dbb37b0adb43d 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -74,9 +74,6 @@ extern void acpi_reserve_bootmem(void); extern void swap_low_mappings(void); -extern void oops_begin(void); -extern void die(const char *,struct pt_regs *,long); -extern void __die(const char * str, struct pt_regs * regs, long err); extern void __show_regs(struct pt_regs * regs); extern void show_regs(struct pt_regs * regs); -- GitLab From a0d58c9741e4ef42f5fbdfb2a6b86f03c6e9092f Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 549/563] [PATCH] x86-64: Set the stack pointer correctly in init_thread and init_tss Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/init_task.c | 2 +- include/asm-x86_64/processor.h | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task.c index c4dc914911574..e0ba5c1043fd2 100644 --- a/arch/x86_64/kernel/init_task.c +++ b/arch/x86_64/kernel/init_task.c @@ -44,6 +44,6 @@ EXPORT_SYMBOL(init_task); * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp; +DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp = INIT_TSS; #define ALIGN_TO_4K __attribute__((section(".data.init_task"))) diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h index c6461c16edbf9..03837d34fba0c 100644 --- a/include/asm-x86_64/processor.h +++ b/include/asm-x86_64/processor.h @@ -254,7 +254,13 @@ struct thread_struct { u64 tls_array[GDT_ENTRY_TLS_ENTRIES]; } __attribute__((aligned(16))); -#define INIT_THREAD {} +#define INIT_THREAD { \ + .rsp0 = (unsigned long)&init_stack + sizeof(init_stack) \ +} + +#define INIT_TSS { \ + .rsp0 = (unsigned long)&init_stack + sizeof(init_stack) \ +} #define INIT_MMAP \ { &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } -- GitLab From a2a0c992e9da823dc23abcb92a42ec5faf856b8b Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 550/563] [PATCH] x86-64: Remove unused vxtime.hz field Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/time.c | 1 - include/asm-x86_64/vsyscall.h | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 7b6abe0582536..6526a19f70eeb 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -937,7 +937,6 @@ void __init time_init(void) vxtime.mode = VXTIME_TSC; vxtime.quot = (1000000L << 32) / vxtime_hz; vxtime.tsc_quot = (1000L << 32) / cpu_khz; - vxtime.hz = vxtime_hz; rdtscll_sync(&vxtime.last_tsc); setup_irq(0, &irq0); diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h index 2872da23fc7ea..438a3f52f839f 100644 --- a/include/asm-x86_64/vsyscall.h +++ b/include/asm-x86_64/vsyscall.h @@ -29,7 +29,6 @@ enum vsyscall_num { struct vxtime_data { long hpet_address; /* HPET base address */ - unsigned long hz; /* HPET clocks / sec */ int last; unsigned long last_tsc; long quot; -- GitLab From 1a426cb76443f5b0a021a9df57d3446d14763c21 Mon Sep 17 00:00:00 2001 From: Jan Beulich <jbeulich@novell.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 551/563] [PATCH] x86-64: Declare NMI_VECTOR and handle it in the IPI sending code. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-x86_64/hw_irq.h | 1 + include/asm-x86_64/ipi.h | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index d9212eb4e8946..dc97668ea0f9d 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -26,6 +26,7 @@ struct hw_interrupt_type; #endif +#define NMI_VECTOR 0x02 /* * IDT vectors usable for external interrupt sources start * at 0x20: diff --git a/include/asm-x86_64/ipi.h b/include/asm-x86_64/ipi.h index 7ba668f43c599..022e9d340ad75 100644 --- a/include/asm-x86_64/ipi.h +++ b/include/asm-x86_64/ipi.h @@ -31,9 +31,20 @@ static inline unsigned int __prepare_ICR (unsigned int shortcut, int vector, unsigned int dest) { - unsigned int icr = APIC_DM_FIXED | shortcut | vector | dest; - if (vector == KDB_VECTOR) - icr = (icr & (~APIC_VECTOR_MASK)) | APIC_DM_NMI; + unsigned int icr = shortcut | dest; + + switch (vector) { + default: + icr |= APIC_DM_FIXED | vector; + break; + case NMI_VECTOR: + /* + * Setup KDB IPI to be delivered as an NMI + */ + case KDB_VECTOR: + icr |= APIC_DM_NMI; + break; + } return icr; } -- GitLab From a2d236b3ac8fcbbf1bae7d815294d258ba24e3f5 Mon Sep 17 00:00:00 2001 From: Jan Beulich <jbeulich@novell.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 552/563] [PATCH] x86-64: Lose constraints on cmpxchg While only cosmetic for x86-64, this adjusts the cmpxchg code appearantly inherited from i386 to use more generic constraints. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-x86_64/system.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h index d65381194bda3..85348e02ad2e1 100644 --- a/include/asm-x86_64/system.h +++ b/include/asm-x86_64/system.h @@ -253,19 +253,19 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, case 2: __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "r"(new), "m"(*__xg(ptr)), "0"(old) : "memory"); return prev; case 4: __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2" : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "r"(new), "m"(*__xg(ptr)), "0"(old) : "memory"); return prev; case 8: __asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2" : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) + : "r"(new), "m"(*__xg(ptr)), "0"(old) : "memory"); return prev; } -- GitLab From 847815760cc0f41985b3185d780aa4369fcb475d Mon Sep 17 00:00:00 2001 From: Chuck Ebbert <76306.1226@compuserve.com> Date: Mon, 12 Sep 2005 18:49:24 +0200 Subject: [PATCH 553/563] [PATCH] x86-64: Clean up nmi error message The x86_64 nmi code is missing a newline in one of its messages. I added a space before the CPU id for readability and killed the trailing space on the previous line as well. Signed-off-by: Chuck Ebbert <76306.1226@compuserve.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/nmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index caf164959e197..330b357940552 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -488,8 +488,8 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) == NOTIFY_STOP) { local_set(&__get_cpu_var(alert_counter), 0); return; - } - die_nmi("NMI Watchdog detected LOCKUP on CPU%d", regs); + } + die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs); } } else { __get_cpu_var(last_irq_sum) = sum; -- GitLab From ff347b221512a83e7b08356729e3e2c14346e29e Mon Sep 17 00:00:00 2001 From: Chuck Ebbert <76306.1226@compuserve.com> Date: Mon, 12 Sep 2005 18:49:25 +0200 Subject: [PATCH 554/563] [PATCH] x86-64: Fix incorrect FP signals This is the same patch that went into i386 just before 2.6.13 came out. I still can't build 64-bit user apps, so I tested with program (see below) in 32-bit mode on 64-bit kernel: Before: $ fpsig handler: nr = 8, si = 0x0804bc90, vuc = 0x0804bd10 handler: altstack is at 0x0804b000, ebp = 0x0804bc7c handler: si_signo = 8, si_errno = 0, si_code = 0 [unknown] handler: fpu cwd = 0xb40, fpu swd = 0xbaa0 handler: i387 unmasked precision exception, rounded up After: $ fpsig handler: nr = 8, si = 0x0804bc90, vuc = 0x0804bd10 handler: altstack is at 0x0804b000, ebp = 0x0804bc7c handler: si_signo = 8, si_errno = 0, si_code = 6 [inexact result] handler: fpu cwd = 0xb40, fpu swd = 0xbaa0 handler: i387 unmasked precision exception, rounded up Signed-off-by: Chuck Ebbert <76306.1226@compuserve.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/traps.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 64a59cb49411a..77658f7f4e845 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -795,13 +795,16 @@ asmlinkage void do_coprocessor_error(struct pt_regs *regs) */ cwd = get_fpu_cwd(task); swd = get_fpu_swd(task); - switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) { + switch (swd & ~cwd & 0x3f) { case 0x000: default: break; case 0x001: /* Invalid Op */ - case 0x041: /* Stack Fault */ - case 0x241: /* Stack Fault | Direction */ + /* + * swd & 0x240 == 0x040: Stack Underflow + * swd & 0x240 == 0x240: Stack Overflow + * User must clear the SF bit (0x40) if set + */ info.si_code = FPE_FLTINV; break; case 0x002: /* Denormalize */ -- GitLab From 9cdd304b20b921507fa1670aaf751496627c8d9c Mon Sep 17 00:00:00 2001 From: Al Viro <viro@ZenIV.linux.org.uk> Date: Mon, 12 Sep 2005 18:49:25 +0200 Subject: [PATCH 555/563] [PATCH] x86-64: more gratitious linux/irq.h includes ... and with that all instances in arch/x86_64 are gone. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/acpi/sleep.c | 1 - arch/x86_64/kernel/apic.c | 1 - arch/x86_64/kernel/crash.c | 1 - arch/x86_64/kernel/i8259.c | 3 --- arch/x86_64/kernel/io_apic.c | 1 - arch/x86_64/kernel/mpparse.c | 1 - arch/x86_64/kernel/nmi.c | 1 - arch/x86_64/kernel/process.c | 1 - arch/x86_64/kernel/smp.c | 1 - arch/x86_64/kernel/smpboot.c | 3 ++- arch/x86_64/kernel/time.c | 1 - arch/x86_64/kernel/traps.c | 3 --- 12 files changed, 2 insertions(+), 16 deletions(-) diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c index 148f6f7ea3158..867a0ebee1773 100644 --- a/arch/x86_64/kernel/acpi/sleep.c +++ b/arch/x86_64/kernel/acpi/sleep.c @@ -34,7 +34,6 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/bootmem.h> -#include <linux/irq.h> #include <linux/acpi.h> #include <asm/mpspec.h> #include <asm/io.h> diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index a759f4e745570..b6e7715d877f3 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -18,7 +18,6 @@ #include <linux/init.h> #include <linux/mm.h> -#include <linux/irq.h> #include <linux/delay.h> #include <linux/bootmem.h> #include <linux/smp_lock.h> diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c index d7fa4248501cc..535e044660798 100644 --- a/arch/x86_64/kernel/crash.c +++ b/arch/x86_64/kernel/crash.c @@ -11,7 +11,6 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/smp.h> -#include <linux/irq.h> #include <linux/reboot.h> #include <linux/kexec.h> diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 909fc63c03b61..b2a238b5a17ed 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -18,15 +18,12 @@ #include <asm/atomic.h> #include <asm/system.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/hw_irq.h> #include <asm/pgtable.h> #include <asm/delay.h> #include <asm/desc.h> #include <asm/apic.h> -#include <linux/irq.h> - /* * Common place to define all x86 IRQ vectors * diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 0645dc835527d..961b519bda567 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -21,7 +21,6 @@ */ #include <linux/mm.h> -#include <linux/irq.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/delay.h> diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index 11642526c5b7e..f16d38d09dafe 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -14,7 +14,6 @@ */ #include <linux/mm.h> -#include <linux/irq.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/config.h> diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index 330b357940552..4388b8a5bae76 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -14,7 +14,6 @@ #include <linux/config.h> #include <linux/mm.h> -#include <linux/irq.h> #include <linux/delay.h> #include <linux/bootmem.h> #include <linux/smp_lock.h> diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 687ed357e685e..b5a89c0bdf591 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -32,7 +32,6 @@ #include <linux/a.out.h> #include <linux/interrupt.h> #include <linux/delay.h> -#include <linux/irq.h> #include <linux/ptrace.h> #include <linux/utsname.h> #include <linux/random.h> diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c index 801db885955ca..9db9dda161b40 100644 --- a/arch/x86_64/kernel/smp.c +++ b/arch/x86_64/kernel/smp.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/mm.h> -#include <linux/irq.h> #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/smp_lock.h> diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 5b7aadbef5f99..e12d7baeb33ec 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -44,7 +44,6 @@ #include <linux/mm.h> #include <linux/kernel_stat.h> #include <linux/smp_lock.h> -#include <linux/irq.h> #include <linux/bootmem.h> #include <linux/thread_info.h> #include <linux/module.h> @@ -58,6 +57,8 @@ #include <asm/tlbflush.h> #include <asm/proto.h> #include <asm/nmi.h> +#include <asm/irq.h> +#include <asm/hw_irq.h> /* Number of siblings per CPU package */ int smp_num_siblings = 1; diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 6526a19f70eeb..2373cb8b86250 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -18,7 +18,6 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/mc146818rtc.h> -#include <linux/irq.h> #include <linux/time.h> #include <linux/ioport.h> #include <linux/module.h> diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 77658f7f4e845..1dfeb07d31ccc 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -47,9 +47,6 @@ #include <asm/proto.h> #include <asm/nmi.h> -#include <linux/irq.h> - - extern struct gate_struct idt_table[256]; asmlinkage void divide_error(void); -- GitLab From aeb39986ec8bf31c8d55eba22f0a9996363482fb Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:25 +0200 Subject: [PATCH 556/563] [PATCH] x86-64: Allow frame pointer and fix help text. Allow frame pointer and fix help text. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- lib/Kconfig.debug | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 3754c9a8f5c8e..016e89a44ac8d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -170,11 +170,11 @@ config DEBUG_FS config FRAME_POINTER bool "Compile the kernel with frame pointers" - depends on DEBUG_KERNEL && ((X86 && !X86_64) || CRIS || M68K || M68KNOMMU || FRV || UML) + depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML) default y if DEBUG_INFO && UML help If you say Y here the resulting kernel image will be slightly larger - and slower, but it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame pointers. + and slower, but it might give very useful debugging information + on some architectures or you use external debuggers. + If you don't debug the kernel, you can say N. -- GitLab From c47a3167d0454c0af5fb0a0322b01a0e3487798e Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:25 +0200 Subject: [PATCH 557/563] [PATCH] x86-64: Make dmi_find_device for !DMI case inline Otherwise it will generate warnings and be generated many times. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/linux/dmi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/dmi.h b/include/linux/dmi.h index c30175e8dec67..a415f1d93e9a4 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -70,7 +70,7 @@ extern struct dmi_device * dmi_find_device(int type, const char *name, static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } static inline char * dmi_get_system_info(int field) { return NULL; } -static struct dmi_device * dmi_find_device(int type, const char *name, +static inline struct dmi_device * dmi_find_device(int type, const char *name, struct dmi_device *from) { return NULL; } #endif -- GitLab From 049cdefe19f95b67b06b70915cd8e4ae7173337a Mon Sep 17 00:00:00 2001 From: Jan Beulich <jbeulich@novell.com> Date: Mon, 12 Sep 2005 18:49:25 +0200 Subject: [PATCH 558/563] [PATCH] x86-64: reduce x86-64 bug frame by 4 bytes As mentioned before, the size of the bug frame can be further reduced while continuing to use instructions to encode the information. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/kernel/traps.c | 8 ++++---- include/asm-x86_64/bug.h | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 1dfeb07d31ccc..b5e09e6b55368 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -321,13 +321,13 @@ void handle_BUG(struct pt_regs *regs) if (__copy_from_user(&f, (struct bug_frame *) regs->rip, sizeof(struct bug_frame))) return; - if ((unsigned long)f.filename < __PAGE_OFFSET || + if (f.filename >= 0 || f.ud2[0] != 0x0f || f.ud2[1] != 0x0b) return; - if (__get_user(tmp, f.filename)) - f.filename = "unmapped filename"; + if (__get_user(tmp, (char *)(long)f.filename)) + f.filename = (int)(long)"unmapped filename"; printk("----------- [cut here ] --------- [please bite here ] ---------\n"); - printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", f.filename, f.line); + printk(KERN_ALERT "Kernel BUG at %.50s:%d\n", (char *)(long)f.filename, f.line); } #ifdef CONFIG_BUG diff --git a/include/asm-x86_64/bug.h b/include/asm-x86_64/bug.h index eed785667289f..80ac1fe966ac1 100644 --- a/include/asm-x86_64/bug.h +++ b/include/asm-x86_64/bug.h @@ -9,10 +9,8 @@ */ struct bug_frame { unsigned char ud2[2]; - unsigned char mov; - /* should use 32bit offset instead, but the assembler doesn't - like it */ - char *filename; + unsigned char push; + signed int filename; unsigned char ret; unsigned short line; } __attribute__((packed)); @@ -25,8 +23,8 @@ struct bug_frame { The magic numbers generate mov $64bitimm,%eax ; ret $offset. */ #define BUG() \ asm volatile( \ - "ud2 ; .byte 0xa3 ; .quad %c1 ; .byte 0xc2 ; .short %c0" :: \ - "i"(__LINE__), "i" (__stringify(__FILE__))) + "ud2 ; pushq $%c1 ; ret $%c0" :: \ + "i"(__LINE__), "i" (__FILE__)) void out_of_line_bug(void); #else static inline void out_of_line_bug(void) { } -- GitLab From 66759a01adbfe8828dd063e32cf5ed3f46696181 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert <76306.1226@compuserve.com> Date: Mon, 12 Sep 2005 18:49:25 +0200 Subject: [PATCH 559/563] [PATCH] x86-64: i386/x86-64: Fix time going twice as fast problem on ATI Xpress chipsets Original patch from Bertro Simul This is probably still not quite correct, but seems to be the best solution so far. Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- Documentation/kernel-parameters.txt | 9 +++++++++ arch/i386/kernel/acpi/earlyquirk.c | 7 +++++++ arch/i386/kernel/io_apic.c | 4 ++++ arch/i386/kernel/setup.c | 5 +++++ arch/x86_64/kernel/io_apic.c | 13 +++++++++++++ arch/x86_64/kernel/setup.c | 5 +++++ include/asm-i386/apic.h | 2 ++ include/asm-x86_64/apic.h | 2 ++ 8 files changed, 47 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index db2603ceabba6..7086f0a90d14a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -164,6 +164,15 @@ running once the system is up. over-ride platform specific driver. See also Documentation/acpi-hotkey.txt. + enable_timer_pin_1 [i386,x86-64] + Enable PIN 1 of APIC timer + Can be useful to work around chipset bugs (in particular on some ATI chipsets) + The kernel tries to set a reasonable default. + + disable_timer_pin_1 [i386,x86-64] + Disable PIN 1 of APIC timer + Can be useful to work around chipset bugs. + ad1816= [HW,OSS] Format: <io>,<irq>,<dma>,<dma2> See also Documentation/sound/oss/AD1816. diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c index f1b9d2a46dab8..087ecc67e9b35 100644 --- a/arch/i386/kernel/acpi/earlyquirk.c +++ b/arch/i386/kernel/acpi/earlyquirk.c @@ -15,6 +15,13 @@ static int __init check_bridge(int vendor, int device) if (vendor == PCI_VENDOR_ID_NVIDIA) { acpi_skip_timer_override = 1; } + /* + * ATI IXP chipsets get double timer interrupts. + * For now just do this for all ATI chipsets. + * FIXME: this needs to be checked for the non ACPI case too. + */ + if (vendor == PCI_VENDOR_ID_ATI) + disable_timer_pin_1 = 1; return 0; } diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 35d3ce26a544a..378313b0cce9a 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -60,6 +60,8 @@ int sis_apic_bug = -1; */ int nr_ioapic_registers[MAX_IO_APICS]; +int disable_timer_pin_1 __initdata; + /* * Rough estimation of how many shared IRQs there are, can * be changed anytime. @@ -2211,6 +2213,8 @@ static inline void check_timer(void) setup_nmi(); enable_8259A_irq(0); } + if (disable_timer_pin_1 > 0) + clear_IO_APIC_pin(0, pin1); return; } clear_IO_APIC_pin(0, pin1); diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index f3d808451d253..dc39ca6a7eca8 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -851,6 +851,11 @@ static void __init parse_cmdline_early (char ** cmdline_p) #endif #ifdef CONFIG_X86_LOCAL_APIC + if (!memcmp(from, "disable_timer_pin_1", 19)) + disable_timer_pin_1 = 1; + if (!memcmp(from, "enable_timer_pin_1", 18)) + disable_timer_pin_1 = -1; + /* disable IO-APIC */ else if (!memcmp(from, "noapic", 6)) disable_ioapic_setup(); diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 961b519bda567..522944a000ad9 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -44,6 +44,8 @@ int sis_apic_bug; /* not actually supported, dummy for compile */ static int no_timer_check; +int disable_timer_pin_1 __initdata; + static DEFINE_SPINLOCK(ioapic_lock); /* @@ -297,6 +299,15 @@ void __init check_ioapic(void) #endif /* RED-PEN skip them on mptables too? */ return; + case PCI_VENDOR_ID_ATI: + /* All timer interrupts on atiixp + are doubled. Disable one. */ + if (disable_timer_pin_1 == 0) { + disable_timer_pin_1 = 1; + printk(KERN_INFO + "ATI board detected. Disabling timer pin 1.\n"); + } + return; } /* No multi-function device? */ @@ -1658,6 +1669,8 @@ static inline void check_timer(void) setup_nmi(); enable_8259A_irq(0); } + if (disable_timer_pin_1 > 0) + clear_IO_APIC_pin(0, pin1); return; } clear_IO_APIC_pin(0, pin1); diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 869770da29331..351d8d64c2fbf 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -336,6 +336,11 @@ static __init void parse_cmdline_early (char ** cmdline_p) #endif #endif + if (!memcmp(from, "disable_timer_pin_1", 19)) + disable_timer_pin_1 = 1; + if (!memcmp(from, "enable_timer_pin_1", 18)) + disable_timer_pin_1 = -1; + if (!memcmp(from, "nolapic", 7) || !memcmp(from, "disableapic", 11)) disable_apic = 1; diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index 6a1b1882285c0..8c454aa58ac6b 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -130,6 +130,8 @@ extern unsigned int nmi_watchdog; #define NMI_LOCAL_APIC 2 #define NMI_INVALID 3 +extern int disable_timer_pin_1; + #else /* !CONFIG_X86_LOCAL_APIC */ static inline void lapic_shutdown(void) { } diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h index 1559d78894acc..6c5d5ca8383a2 100644 --- a/include/asm-x86_64/apic.h +++ b/include/asm-x86_64/apic.h @@ -109,6 +109,8 @@ extern unsigned int nmi_watchdog; #define NMI_LOCAL_APIC 2 #define NMI_INVALID 3 +extern int disable_timer_pin_1; + #endif /* CONFIG_X86_LOCAL_APIC */ extern unsigned boot_cpu_id; -- GitLab From e58e0d03120d6c2aa134fd3be4f0f762f0bb25e7 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:25 +0200 Subject: [PATCH 560/563] [PATCH] x86-64: Clean up the SRAT node list before computing the hash function Also use for_each_node_mask instead of hand crafted loops. Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/mm/srat.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 36bc7be9afb98..d66b814e50336 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -177,6 +177,14 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) int i; if (acpi_numa <= 0) return -1; + + /* First clean up the node list */ + for_each_node_mask(i, nodes_parsed) { + cutoff_node(i, start, end); + if (nodes[i].start == nodes[i].end) + node_clear(i, nodes_parsed); + } + memnode_shift = compute_hash_shift(nodes, nodes_weight(nodes_parsed)); if (memnode_shift < 0) { printk(KERN_ERR @@ -184,16 +192,10 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) bad_srat(); return -1; } - for (i = 0; i < MAX_NUMNODES; i++) { - if (!node_isset(i, nodes_parsed)) - continue; - cutoff_node(i, start, end); - if (nodes[i].start == nodes[i].end) { - node_clear(i, nodes_parsed); - continue; - } + + /* Finally register nodes */ + for_each_node_mask(i, nodes_parsed) setup_node_bootmem(i, nodes[i].start, nodes[i].end); - } for (i = 0; i < NR_CPUS; i++) { if (cpu_to_node[i] == NUMA_NO_NODE) continue; -- GitLab From 2bce2b54ae91aac76b62e8110b627ba5e5cbbffd Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:25 +0200 Subject: [PATCH 561/563] [PATCH] x86-64: reset apicid<->node tables when SRAT cannot be parsed Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/mm/srat.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index d66b814e50336..07bf13fbcf84c 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -81,8 +81,11 @@ static __init void cutoff_node(int i, unsigned long start, unsigned long end) static __init void bad_srat(void) { + int i; printk(KERN_ERR "SRAT: SRAT not used.\n"); acpi_numa = -1; + for (i = 0; i < MAX_LOCAL_APIC; i++) + apicid_to_node[i] = NUMA_NO_NODE; } static __init inline int srat_disabled(void) -- GitLab From 4b6a455c7472dabcc624faa740a297d50815b4c7 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:25 +0200 Subject: [PATCH 562/563] [PATCH] x86-64: Use correct mask to compute conflicting nodes in SRAT The nodes are not set online yet at this point. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- arch/x86_64/mm/srat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 07bf13fbcf84c..4b2e844c15a75 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -50,7 +50,7 @@ static __init int setup_node(int pxm) static __init int conflicting_nodes(unsigned long start, unsigned long end) { int i; - for_each_online_node(i) { + for_each_node_mask(i, nodes_parsed) { struct node *nd = &nodes[i]; if (nd->start == nd->end) continue; -- GitLab From 2ade81473636b33aaac64495f89a7dc572c529f0 Mon Sep 17 00:00:00 2001 From: Andi Kleen <ak@suse.de> Date: Mon, 12 Sep 2005 18:49:25 +0200 Subject: [PATCH 563/563] [PATCH] x86-64: clean up local_add/sub arguments Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- include/asm-x86_64/local.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-x86_64/local.h b/include/asm-x86_64/local.h index c954f15c1a755..3e72c41727c53 100644 --- a/include/asm-x86_64/local.h +++ b/include/asm-x86_64/local.h @@ -29,7 +29,7 @@ static __inline__ void local_dec(local_t *v) :"m" (v->counter)); } -static __inline__ void local_add(unsigned long i, local_t *v) +static __inline__ void local_add(unsigned int i, local_t *v) { __asm__ __volatile__( "addl %1,%0" @@ -37,7 +37,7 @@ static __inline__ void local_add(unsigned long i, local_t *v) :"ir" (i), "m" (v->counter)); } -static __inline__ void local_sub(unsigned long i, local_t *v) +static __inline__ void local_sub(unsigned int i, local_t *v) { __asm__ __volatile__( "subl %1,%0" -- GitLab